深入学习委托

从学.net至今,委托一直是一个难以理解的概念,对于初学者来说更是朦胧模糊,尝尝看到院子里的大神说:“委托本质就是一个类”,确实委托Delegate是一个类:
    [Serializable]
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [System.Runtime.InteropServices.ComVisible(true)]
    public abstract class Delegate : ICloneable, ISerializable 
    {
        [System.Security.SecurityCritical]
        internal Object _target;

        [System.Security.SecurityCritical]
        internal Object _methodBase;

        [System.Security.SecurityCritical]
        internal IntPtr _methodPtr;
        
        [System.Security.SecurityCritical]
        internal IntPtr _methodPtrAux;

        [System.Security.SecuritySafeCritical] 
        protected Delegate(Object target,String method)
        {
            if (target == null)
                throw new ArgumentNullException("target");
            
            if (method == null)
                throw new ArgumentNullException("method");
            Contract.EndContractBlock();
            
            if (!BindToMethodName(target, (RuntimeType)target.GetType(), method,
                                  DelegateBindingFlags.InstanceMethodOnly |
                                  DelegateBindingFlags.ClosedDelegateOnly))
                throw new ArgumentException(Environment.GetResourceString("Arg_DlgtTargMeth"));
        }
            
        [System.Security.SecuritySafeCritical]  
        protected unsafe Delegate(Type target,String method)
        {
            if (target == null)
                throw new ArgumentNullException("target");

            if (target.IsGenericType && target.ContainsGenericParameters)
                throw new ArgumentException(Environment.GetResourceString("Arg_UnboundGenParam"), "target");

            if (method == null)
                throw new ArgumentNullException("method");
            Contract.EndContractBlock();

            RuntimeType rtTarget = target as RuntimeType;
            if (rtTarget == null)
                throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"), "target");

            BindToMethodName(null, rtTarget, method,
                             DelegateBindingFlags.StaticMethodOnly |
                             DelegateBindingFlags.OpenDelegateOnly |
                             DelegateBindingFlags.CaselessMatching);
        }
            
        // Protect the default constructor so you can't build a delegate
        private Delegate() //防止Delegate在类的外部new对象
        {
        }
    }
这是Delegate类源码的部分展示。确实可以说明委托其实就是类,那我们定义的委托是什么呢?下面我们通过IL来分析一下,首先看我们用C#定义一个委托:
    public class DelegateClass
    {
        public delegate void OneMethod(string name);

        public abstract class OneClass//用于对比上面定义的委托,无实际意义
        {
            public abstract void BeginInvoke();

            public abstract void EndInvoke();

            public abstract void Invoke(string name);
        }

        public string Name;

        public void Main()
        {
            var oneMethod = new OneMethod((m) => Console.WriteLine(Name + " hahaha,sb!"));
            oneMethod += m => Console.WriteLine(m + " heiheihei,nc!");
            oneMethod.Invoke("wangqi");
            oneMethod("wangqi");
        }
    }
IL的成员展示:

可以看出自定义的委托OneMethod和OneClass都描述为.class,说明我们自定义的委托和我们自定义的类是一样的。区别在于:自定义的委托会自动生成构造函数(.ctor),异步调用方法BeginInvoke、EndInvoke,同步调用方法Invoke。

这里我们再做观察,发现extends System,MulticastDelegate,原来我们在用“委托”并不是直接继承自Delegate类的,而是继承自MulticastDelegate类(ps:MulticastDelegate继承自Delegate),也就是我们所说的多播委托。

再来看一下我们委托的调用,首先我们注册了2个匿名方法,然后执行了oneMethod.Invoke("wangqi")和oneMethod("wangqi"),那么这2个是否有区别呢?我们来开IL Mian方法的描述:


发现两者其实都是调用Invoke方法,并无差别,这也是我们平时用的比较多的委托调用。

BeginInvoke和EndInvoke主要用于多线程的编程,具体请参考:C#综合揭秘——细说多线程(上)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值