从学.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#综合揭秘——细说多线程(上)