Demystifying Delegates

首先瞅一下委托的定义:

public delegate void Feedback(object value);

编译器将之翻译后的代码:

public class Feedback:System.MulticastDelegate
{
  //构造函数
  public Feedback(object target,Int32 methodPtr);
  //委托对象调用回调函数的方法
  public void virtual Invoke(object value);
  //用于委托对异步回调的支持
  public virtual IAsyncResult BeginInvoke(object value,AsyncCallback callback,Object object);
  public virtual void EndInvoke(IAsyncResult result);
}

从编译器生成的源码可以看出:委托类 Feedback继承自System.MulticastDelegate,MulticastDelegate的有三个重要私有字段是_target(指向回调函数被调用时操作的对象,该字段用于实例方法的回调,如果是静态方法为NULL),_methodPtr(用于标识指定的回调方法),_prev(指向另一个委托对象,用于形成委托链)。_target 和 methodPtr两个参数在委托构造函数中被初始化。委托对象就是对方法及调用时操作的对象的一个封装。Invoke方法的返回值类型及参数与委托签名一致,使用_target和_methodPtr来确定在指定对象上调用指定的方法。MulticastDelegate提供了两个公共只读属性Target和Method,用于获取委托的封装信息。一个类期望调用另一个类的私有方法,可以通过将该私有方法做一个委托封装来实现。

Delegate与MulticastDelegate间的关系

System.MultiCastDelegate继承自System.Delegate,.net框架起初设计是两种委托类型:single-cast,multicast,delegate被设计成一个基类型,用于实现回调一个方法所必要的功能,而multicastDelegate用于支持委托对象链表,即void返回值原型方法的委托链。而在.net框架开发周期的后期,发现一些的缺陷,如一些情况下方法的返回值是非void值,但返回值可以忽略,但却不可以放到委托链中。鉴于多种限制,.net框架组后期在编译器上将这两个类进行了合并,为了支持委托链,编译器产生的委托类都继承自MutlicastDelegate。

委托链的形成

委托链即指一个MulcastDelegate对象指向另一个MulticastDelegate对象的引用,形成一个链表,利用的是MulticastDelegate字段_prev。

Class System.Delegate{
//head是最后一个被调用的委托对象
public static Delegate Combine(Delegate tail,Delegate head);

public static Delegate Combine(Delegate[] delegateArray);

public static Delegate Remove(Delegate source,Delegate value);
}

当构造一个新的委托对象时,其_prev=null,利用combine形成委托链,新添加的委托对象位于委托链表的head,而它的_prev字段指向原委托链的head。调用一个委托对象会导致它前面的委托首先被调用,在调用前面的委托之后,委托对象才会调用自己封装的回调目标及回调方法(head是最后一个被调用的委托对象)。调用委托对象时实则是对该委托类型的Invoke方法的调用。委托对象一旦被构造,它们就认为是恒定不变的,也就是说在调用combine将一个委托对象给合到一个委托链中时,内部会构造一个新的委托对象,但是其_prev字段指向原委托链的head。

原文地址:https://www.cnblogs.com/spirit/p/1561541.html