委托的理解

来源:互联网 发布:淘宝详情图怎么加链接 编辑:程序博客网 时间:2024/05/18 01:26

委托

一、委托的使用

一个简单委托的构成
1.声明委托类型;
2.必须有一个方法包含了要执行的代码;
3.必须创建一个委托实例;
4.必须调用(invoke)委托实例;

以一个简单的计算类来介绍吧!首先,需要声明一个委托类型:
//声明委托public delegate int Calculate(int num1,int num2);
接下来,我们来实现委托所需要实现的方法,这里我在一个静态类中实现了加减乘除:
public static class NumCalculate    {        /// <summary>        ///        /// </summary>        /// <param name="num1"></param>        /// <param name="num2"></param>        /// <returns></returns>        public static int Sum(int num1, int num2)        {            return num1 + num2;        }        /// <summary>        ///        /// </summary>        /// <param name="num1"></param>        /// <param name="num2"></param>        /// <returns></returns>        public static int subtract(int num1,int num2)        {            return num1 - num2;        }        /// <summary>        ///        /// </summary>        /// <param name="num1"></param>        /// <param name="mun2"></param>        /// <returns></returns>        public static int mutiply(int num1,int num2)        {            return num1 * num2;        }        /// <summary>        ///        /// </summary>        /// <param name="num1"></param>        /// <param name="num2"></param>        /// <returns></returns>        public static int divide(int num1,int num2)        {            if (num2==0)            {                return 0;            }            else            {                return num1 / num2;            }        }    }

接下来,需要创建一个委托的实例:

//创建委托实例Calculate calculate = new Calculate(NumCalculate.Sum);

最后调用委托实例,就可以了。

int num1 = 6;int num2 = 3;int result = 0;result = calculate(num1, num2);

将结果输出后,可以看到result的值为:
result的值

委托的介绍

委托的原理

再来看一看刚才的委托声明:

//声明委托public delegate int Calculate(int num1,int num2);

根据CLR via C#的解释,编译器将会将会定义一个完整的类,通过ildasm反编译刚才生成的dll,就可以看到CLR所说的由编译器生成的类:
反编译的结果

可以看到编译器定义的类有4个方法:一个构造器、BeginInvoke、EndInvoke和Invoke;并且可以看到这个类继承自System.MulticastDelegate。其实,当我们调用委托时,其实是调用的委托的Invoke方法。当然我们显示的调用Invoke方法也是可以得。

result = calculate.Invoke(num1,num2);

上面那行代码和前面的调用代码将会得到一样的结果。

委托的执行顺序

委托支持委托链,委托链就是委托对象的集合。当调用委托实例时,将会按顺序执行委托链中的方法。不过这里需要注意,当调用返回值不为void的委托实例时,返回值将是委托链中最后一个方法的值。将上面的代码修改成如下时:

Calculate calculate = new Calculate(NumCalculate.Sum);calculate += NumCalculate.divide;int num1 = 6;int num2 = 3;int result = 0;result = calculate(num1, num2);

运行程序,将会得到如下的结果:
result的结果
为了进一步探究委托链的原理,在委托赋值完成之后加上断点。如下所示,可以看到_invovationList包含2个成员,即我们刚才添加的2个方法。当调用委托的实例时,将会按顺序执行这2个方法,并且将最后一个方法的返回值复制给result。
委托链
对于委托实例中方法的赋值和删除,可以很方便的使用+=和-=来实现,这2个操作符本质上是对Delegate类型的Combine和Remove静态方法的调用。
此外,CLR via C#还对委托的Invoke方法进行了实现,具体伪代码如下:

public Int32 Invoke(Int32 value1,Int32 value2){    Int32 result;    Delegate[] delegateSet=_invocationList as Delegate[];    if(delegateSet!=null){        //这个委托数组指定了应该调用的委托        foreach(Calculate d in delegateSet)            result=d(value1,value2);//调用每个委托    }else{ //否则就不是委托链        //该委托标识了要回调的回调单个方法,        //在指定的目标对象上调用这个回调方法        result=_methodPtr.Invoke(_target,value1,value2);        //上面这行代码接近实际的代码,        //实际发生的事情用C#是表示不出来的   }   return result;}

通过上面的伪代码,当数组中的每个委托被调用时,其返回值被保存到result变量中。循环完成后,result变量只包含调用的最后一个委托的结果(前面的返回值会被覆盖掉),该值最后会返回给调用Invoke的代码。这也说明了上面提到的:当调用返回值不为void的委托实例时,返回值将是委托链中最后一个方法的值。

总结

1.为了创建委托实例,需要一个方法以及(对于实例方法来说)调用方法的目标;
2.委托封装了包含特殊返回类型和一组参数的行为,类似于包含单一方法的接口;
3.委托实例可以合并到一起,也可以从一个委托实例中删除另一个;
4.每个委托实例都包含一个调用列表。


本文参考CLR via C#、深入理解C#

原创粉丝点击