CLR via C#第17章:委托

委托的使用就不必多说。

本文主要是要将委托的继承关系和一些细节。

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方法。用于显示调用委托链中的每一个委托。

  1. 如果委托是由返回值的时候,其实最后只会返回最后一个委托的返回值,因为每个委托被调用时,其返回值都会被保存到result变量中,但是执行到后面的委托后,就会覆盖前面的保存下来的值。
  2. 此外,如果这些委托中有一个委托出错或者阻塞住,就会导致后面的委托无法执行。

看完这章之后有个疑问:

委托执行del("")和del.Invoke("")是一样的效果。使用IDSAM.exe查看。定义一个委托的时候,实际上是创建了一个密封类,这个密封类编译器会自动创建4个方法:一个构造器,Invoke,BeginInvole,EndInvoke。后三个函数是虚函数,实际上MulticastDelegate和Delegate这两个类是找不到这三个函数的。疑问:IDSAM.exe上显示后三个函数是空的????空函数体是怎么去实现委托调用的???

猜你喜欢

转载自blog.csdn.net/maoxiaohai123/article/details/84836443
今日推荐