日期:2013-07-19  浏览次数:20452 次

第十二章 委托

一、 委托的使用

静态委托和实例委托,使用方法类似,这里给出一个使用可变参数委托的例子:

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