第十二章 委托
一、             委托的使用
静态委托和实例委托,使用方法类似,这里给出一个使用可变参数委托的例子:
using System; 
public class DelCls
{
       public delegate void DelDef(params string[] strParams); 
       public static void CallDel(DelDef dd)
       {
              if(dd != null)   //请务必在此处进行判断,这是个好习惯
              {
                     dd("Hello", "world");
              }
       }
} 
public class DelIns
{
       //声明为private(私有)成员并不影响在类型内部使用委托
       private static void ClsCallStr(params string[] strParams)     //类型方法
       {
              //将字符串数组并顺序输出
              foreach(string str in strParams)
              {
                     Console.Write("{0} ", str);
              }
              Console.WriteLine();
       }       
       public void InsCallStr(params string[] strParams)              //实例方法
       {
              //将字符串数组并反序输出
              for(int i = strParams.Length - 1; i >= 0; i --)
              {
                     Console.Write("{0} ", strParams[i]);
              }                   
              Console.WriteLine();
       }       
       public static void Main()
       {
              DelIns di = new DelIns();              
              DelCls.DelDef dd = null;
              Console.WriteLine("combine two delegate:");
              dd += new DelCls.DelDef(DelIns.ClsCallStr);
              dd += new DelCls.DelDef(di.InsCallStr);
              DelCls.CallDel(dd);              
              Console.WriteLine("remove the first delegate:");
              dd -= new DelCls.DelDef(DelIns.ClsCallStr);
              DelCls.CallDel(dd);
       }
} 
/*运行结果
combine two delegate:
Hello world
world Hello
remove the first delegate:
world Hello
*/
在C#中使用委托方法:
l         创建委托所使用的方法必须和委托声明相一致(参数列表、返回值都一致)
l         利用 +=、-=来进行委托的链接或取消链接或直接使用Delegate.Combine和Delegate.Remove方法来实现
l         使用MulticastDelegate的实例方法GetInvocationList()来获取委托链中所有的委托 
二、             委托揭秘
所有的委托都继承自MulticastDelegate,编译器在编译时刻为委托的声明生成了一个完整的委托类,重点注意其中的一些成员:
ü         构造函数,传入委托的目标对象(实例)及指向回调方法的整数
ü         继承自MulticastDelegate的_target(System.Object)字段
ü         继承自MulticastDelegate的_methodPtr(System.Int32)字段
ü         继承自MulticastDelegate的_prev(System.MulticastDelegaet)字段
ü         生成的与方法声明相一致Invoke函数用以调用方法
可利用MulticastDelegate中的Method及Target属性来考察_methodPtr及_target字段的性质。
关于编译器生成的委托类及Invoke方法的调用情况,可通过使用ILDAsm.exe查看执行文件的IL代码获得
将上例中类型DelIns中的Main方法作如下修改,以实验GetInvocationList及MulticastDelegate中属性的使用:
public class DelIns
{
…
       public static void Main()
       {
              …
              Delegate[] arrDel = dd.GetInvocationList();
              foreach(DelCls.DelDef d in arrDel)
              {
                     Console.WriteLine("Object type: {0}, Method name: {1}", 
                                                        (d.Target != null) ? d.Target.GetType().ToString() : "null", 
                                                        d.Method.Name);   
              }
              …
       }
…
}
/*运行结果
…
Object type: null, Method name: ClsCallStr
Object type: DelIns, Method