委托的使用就不必多说。
本文主要是要将委托的继承关系和一些细节。
FCL中有两个委托类。MulticastDelegate和Delegate前者也继承自后者。
查看源码知道Delegate是有四个私有字段的:
// _target is the object we will invoke on
[System.Security.SecurityCritical]
internal Object _target;
// MethodBase, either cached after first request or assigned from a
DynamicMethod
// For open delegates to collectible types, this may be a LoaderAllocator
object
[System.Security.SecurityCritical]
internal Object _methodBase;
// _methodPtr is a pointer to the method we will invoke
// It could be a small thunk if this is a static or UM call
[System.Security.SecurityCritical]
internal IntPtr _methodPtr;
// In the case of a static method passed to a delegate, this field stores
// whatever _methodPtr would have stored: and _methodPtr points to a
// small thunk which removes the "this" pointer before going on
// to _methodPtrAux.
[System.Security.SecurityCritical]
internal IntPtr _methodPtrAux;
在MSDN中显示的是Delegate有两个公开的属性Method和Target。前者是标志 委托的函数。后者引用委托函数的实例(如果委托函数是静态函数,则Target为null)。
此处为什么源码和MSDN中显示会不一样呢?如果有知道答案的大佬请留言,,感激。。。。
在MulticastDelegate中添加了这两个私有变量,当然,在微软官网上公开的还是那两个字段。
[System.Security.SecurityCritical]
private Object _invocationList;
[System.Security.SecurityCritical]
private IntPtr _invocationCount;
class Program
{
delegate void TwoLongSop(string firer);
static void Main(string[] args)
{
TwoLongSop del1 = new TwoLongSop(new Program().Dele1);
TwoLongSop del2 = new TwoLongSop(new Program().Dele2);
TwoLongSop del3 = new TwoLongSop(new Program().Dele3);
TwoLongSop stss = new TwoLongSop(Program.st);
TwoLongSop del = null;
del = (TwoLongSop)Delegate.Combine(del, del1);
del = (TwoLongSop)Delegate.Combine(del, del2);
del = (TwoLongSop)Delegate.Combine(del, del3);
Delegate[] sum= del.GetInvocationList();
Console.ReadKey();
}
private void Dele1(string str)
{
Console.WriteLine(str);
}
private void Dele2(string str)
{
Console.WriteLine(str);
}
private void Dele3(string str)
{
Console.WriteLine(str);
}
private static void st(string str)
{
}
}
当代码执行到
del = (TwoLongSop)Delegate.Combine(del, del1);
处时,会调用Delegate的Combine方法(委托的重载操作符+=实际上就是执行这一个函数),然后del就指向del1委托实例。之后在委托链中添加第二个委托时,Combine方法发现del已经引用了一个委托对象,所以此时Combine会构造一个新的委托对象,这个新的委托对象初始化。这个新建的委托对象的invocationList字段被初始化为引用一个委托对象数组。del不再指向del1而是指向这个新建的委托对象。这个新建的委托对象的委托对象数组的第一个元素是Dele1函数,第二个元素是Dele2函数。之后,继续调用Combine函数,则会再次重新创建一个委托对象,del指向这个新建的委托对象。(之前新建的委托对象和委托链数组可以进行垃圾回收了)。
由此可知:可以不断的往委托链中添加委托实现执行多个委托。但是此处有两点需要注意:
MulticastDelegate 提供了一个实例方法GetInvocationList方法。用于显示调用委托链中的每一个委托。
- 如果委托是由返回值的时候,其实最后只会返回最后一个委托的返回值,因为每个委托被调用时,其返回值都会被保存到result变量中,但是执行到后面的委托后,就会覆盖前面的保存下来的值。
- 此外,如果这些委托中有一个委托出错或者阻塞住,就会导致后面的委托无法执行。
看完这章之后有个疑问:
委托执行del("")和del.Invoke("")是一样的效果。使用IDSAM.exe查看。定义一个委托的时候,实际上是创建了一个密封类,这个密封类编译器会自动创建4个方法:一个构造器,Invoke,BeginInvole,EndInvoke。后三个函数是虚函数,实际上MulticastDelegate和Delegate这两个类是找不到这三个函数的。疑问:IDSAM.exe上显示后三个函数是空的????空函数体是怎么去实现委托调用的???