.net中定义了2种不同类型的委托:单播委托System.Delegate和多播委托System.MulticastDelegate.
而在实际中,我们创建的所有委托类型都是以MulticastDelegate为基类的。(因为MulticastDelegate继承自Delegate,后者的2个静态方法Combine和Remove也经常使用。)
由此可知,我们创建的委托都允许维护一个委托链表,将回调方法或者说此委托类型的实例放到委托链表中。通过重载的操作符:+=和-=可以完成上链和移除的操作,其背后就是调用Combine和Remove方法。
在class MouseFamily中定义的委托:
class MouseFamily
{
//定义Feedback委托类型
public delegate void Feedback(string mouseName, int num);
private string[] mice;
public MouseFamily(string[] mouseName)
{
mice=new string[mouseName.Length];
for (int i = 0; i < mouseName.Length; i++)
mice[i] = mouseName[i];
}
public void Run(Feedback feedback)
{
for (int i = 0; i < mice.Length; i++)
{
if (feedback != null)
feedback(mice[i], i + 1);
}
}
}
编译器遇到public delegate void Feedback(string mouseName, int num);这句时,会产生如下一个类的定义:
public class Feedback : System.MulticastDelegate {
//构造函数
public Feedback(Object target,Int32 methodPtr);
//类似于函数的签名,和原型函数一致
public void virtual Invoke(string mouseName,Int32 num);
//允许进行异步的回调
public virtual IAsyncResult BeginInvoke(string mouseName,
Int32 num,
AsyncCallback callback,Object object);
//等待异步的返回
public virtual void EndInvoke(IAsyncResult result);
}
ILDasm查看:
Delegate类有四个私有字段:
1、private Object _target;
2、private IntPtr _methodPtr;
3、private IntPtr _methodPtrAux;
4、private RuntimeMethodInfo _method;
其中_target是调用方法的对象实例的引用,如果调用方法是static的,那么就不存在对象实例的引用,这时target为null。_methodPtr是用来标识要调用的方法(一个特殊的标识方法的Int32值)
在上面的Feedback委托中,Feedback的构造构数就是将_taget和_methodPtr进行初始化。
MulticastDelegate类自己增加了个私有字段:
private MulticastDelegate _prev;
_prev用于指向另一个委托对象,实现链表。
当回调方法时,feedback+=new MouseFamily.Feedback(Tom.Cry)
回调方法产生的代码像编译下面的代码一样
feedback.Invok(mouseName,num);