委托
1 请解释委托的基本原理
2 委托回调静态方法和实例方法有何区别
3 什么是链式委托
4 链式委托的执行顺序是怎么样的
5 可否定义拥有返回值的方法的委托链
6 委托通常可以应用在哪些场合
委托是一个钟数据类型,用来传递方法。委托类型继承自System.Delegate,自定义委托类型都直接继承自System.NulticastDelegate,System.NulticastDelegate又继承自System.Delegate。每个委托至少包含一个指向某个方法的指针,该方法可以是实例方法,也可以是静态方法。委托实现了回调方法的机制,能够帮助程序员设计出更加简洁优美的面向对象程序。
示例:
class SimpleDelegate { /// <summary> /// 定义的委托。 /// </summary> /// <param name="i">接受一个整型参数</i> public delegate void TestDelegate(int i); static void Main(string[] args) { //调用委托方法 TestDelegate d = new TestDelegate(PrintMessage1); //或者直接写TestDelegate d = PrintMessage1; d(0); d(1); Console.Read(); } /// <summary> /// 一个静态方法,符合TestDelegate的定义 /// </summary> /// <param name="i">整型参数</param> static void PrintMessage1(int i) { Console.WriteLine("第" + i + "个方法"); } }
输出:
第0个方法
第1个方法
本质上,委托的调用就是执行了定义在委托所生成的Invoke方法。
完全可以这样调用:
d.Invoke(0);
d.Invoke(1);
当一个实例方法被调用时,需要通过实例对象来访问,绑定一个实例方法到委托必须同时让委托得到实例的方法的代码段和实例对象的信息,这样委托在被回调的时候.NET才能成功地执行实例方法。
用Reflector查看的部分System.Delegate代码:
_target是一个指向目标实例的引用。当绑定一个实例方法给委托时,该参数会被设置为该方法所在类型的一个实例对象。而当绑定一个静态方法给委托时,该参数则被设置为null。
_mathodPtr是一个指向绑定方法代码段的指针。绑定静态方法还是实例方法在这个成员的设置上并没有不同。
也叫多播委托。所有自定义委托都直接继承自System.MulticastDelegate类型。这个类型即是为链表委托而设计的。
链式委托是指一个由委托串成的链表,当链表中的一个委托被回调时,所有链表上该委托的后续委托都将会被顺序执行。
示例:
class MulticastDelegate { /// <summary> /// 定义的委托。 /// </summary> public delegate void TestMultiDelegate(); static void Main(string[] args) { //申明一个委托变量,并绑定第一个方法 TestMultiDelegate handler = PrintMessage1; //绑定第二个方法 handler += PrintMessage2; //绑定第三个方法 handler += PrintMessage3; //检查结果 handler(); Console.Read(); } static void PrintMessage1() { Console.WriteLine("第一个方法"); } static void PrintMessage2() { Console.WriteLine("第二个方法"); } static void PrintMessage3() { Console.WriteLine("第三个方法"); } }
输出:
第一个方法
第二个方法
第三个方法
用Reflector查看编译后的Main方法:
private static void Main(string[] args) { TestMultiDelegate handler = new TestMultiDelegate(Program.PrintMessage1); handler = (TestMultiDelegate) Delegate.Combine(handler, new TestMultiDelegate(Program.PrintMessage2)); handler = (TestMultiDelegate) Delegate.Combine(handler, new TestMultiDelegate(Program.PrintMessage3)); handler(); Console.Read(); }
调用Delegate.Combine方法 详细内容可查看GitHub中Delegate源码
public static Delegate Combine(Delegate a, Delegate b) { if ((Object)a == null) // cast to object for a more efficient test return b; return a.CombineImpl(b); }
在调用CombineImpl方法
protected virtual Delegate CombineImpl(Delegate d) { throw new MulticastNotSupportedException(Environment.GetResourceString("Multicast_Combine")); }
MulticastDelegate重写了这个方法:详细内容可查看GitHub中MulticastDelegate源码
1 // This method will combine this delegate with the passed delegate 2 // to form a new delegate. 3 [System.Security.SecuritySafeCritical] // auto-generated 4 protected override sealed Delegate CombineImpl(Delegate follow) 5 { 6 if ((Object)follow == null) // cast to object for a more efficient test 7 return this; 8 9 // Verify that the types are the same... 10 if (!InternalEqualTypes(this, follow)) 11 throw new ArgumentException(Environment.GetResourceString("Arg_DlgtTypeMis")); 12 13 MulticastDelegate dFollow = (MulticastDelegate)follow; 14 Object[] resultList; 15 int followCount = 1; 16 Object[] followList = dFollow._invocationList as Object[]; 17 if (followList != null) 18 followCount = (int)dFollow._invocationCount; 19 20 int resultCount; 21 Object[] invocationList = _invocationList as Object[]; 22 if (invocationList == null) 23 { 24 resultCount = 1 + followCount; 25 resultList = new Object[resultCount]; 26 resultList[0] = this; 27 if (followList == null) 28 { 29 resultList[1] = dFollow; 30 } 31 else 32 { 33 for (int i = 0; i < followCount; i++) 34 resultList[1 + i] = followList[i]; 35 } 36 return NewMulticastDelegate(resultList, resultCount); 37 } 38 else 39 { 40 int invocationCount = (int)_invocationCount; 41 resultCount = invocationCount + followCount; 42 resultList = null; 43 if (resultCount <= invocationList.Length) 44 { 45 resultList = invocationList; 46 if (followList == null) 47 { 48 if (!TrySetSlot(resultList, invocationCount, dFollow)) 49 resultList = null; 50 } 51 else 52 { 53 for (int i = 0; i < followCount; i++) 54 { 55 if (!TrySetSlot(resultList, invocationCount + i, followList[i])) 56 { 57 resultList = null; 58 break; 59 } 60 } 61 } 62 } 63 64 if (resultList == null) 65 { 66 int allocCount = invocationList.Length; 67 while (allocCount < resultCount) 68 allocCount *= 2; 69 70 resultList = new Object[allocCount]; 71 72 for (int i = 0; i < invocationCount; i++) 73 resultList[i] = invocationList[i]; 74 75 if (followList == null) 76 { 77 resultList[invocationCount] = dFollow; 78 } 79 else 80 { 81 for (int i = 0; i < followCount; i++) 82 resultList[invocationCount + i] = followList[i]; 83 } 84 } 85 return NewMulticastDelegate(resultList, resultCount, true); 86 } 87 }