C# Delegate,看起来和函数指针很类似,我简单理解为安全的方法套
直接看代码来理解CLR之上的机制,废话不说
对于一个简单的委托
public delegate int BinaryOp(int x, int y);
它将展开为
sealed class BinaryOp : System.MulticastDelegate
{
public BinaryOp(object target, uint functionAddress);
public void Invoke(int x, int y);
public IAsyncResult BeginInvoke(int x, int y,
AsyncCallback cb, object state);
public int EndInvoke(IAsyncResult result);
}
注意到这是一个封闭的类,然后提供了异步调用的能力
更泛的情况,一个类似代入公式的伪代码写法:
public sealed class DelegateName : System.MulticastDelegate
{
public DelegateName (object target, uint functionAddress);
public delegateReturnValue Invoke(allDelegateInputParams);
public IAsyncResult BeginInvoke(allDelegateInputRefAndOutParams,
AsyncCallback cb, object state);
public delegateReturnValue EndInvoke(allDelegateRefAndOutParams,
IAsyncResult result);
}
然后顺着继承树往上摸索,看看System.MulticastDelegate的部分成员
[Serializable]
public abstract class MulticastDelegate : Delegate
{
// Methods
public sealed override Delegate[] GetInvocationList();
// Overloaded operators
public static bool operator ==(MulticastDelegate d1, MulticastDelegate d2);
public static bool operator !=(MulticastDelegate d1, MulticastDelegate d2);
// Fields
private IntPtr _invocationCount;
private object _invocationList;
}
这个可串行化标记很奇怪,MulticastDelegate 本身是一个虚类,不可能生成实例,这地方不大理解;根据.NET串行化的特点,该标记不可继承,所以说delegate本身是没有串行化能力的。其他的东西作用比较明显,GetInvocationList()为按调用顺序返回被调用方法列表,两个重载的运算符用来判断2个delegate是否相等(所谓相等,就是有相同的方法挂钩于上),两个私有字段和delegate的Multi-Invocation有关
继续往上,看看Delegate的部分成员
[Serializable, ClassInterface(ClassInterfaceType.AutoDual)]
public abstract class Delegate : ICloneable, ISerializable
{
// Methods
public static Delegate Combine(params Delegate[] delegates);
public static Delegate Combine(Delegate a, Delegate b);
public virtual Delegate[] GetInvocationList();
public static Delegate Remove(Delegate source, Delegate value);
public static Delegate RemoveAll(Delegate source, Delegate value);
// Overloaded operators
public static bool operator ==(Delegate d1, Delegate d2);
public static bool operator !=( Delegate d1, Delegate d2);
// Properties
public MethodInfo Method { get; }
public object Target { get; }
}
Combine()与Remove()、RemoveAll(),加上重载的"="、"+="、"-="、"+"、"-"运算符,我们的单个delegate变量可以操纵一个方法序列,并且我们可以根据自己的需要对这个方法序列进行修改。到这一步对delegate的能力可以了然了,突出表现为异步调用和可定制的多重调用(非认证的说法)。
下面随手写个例子看看,来集中体现delegate的性质和用法
class Program
{
public delegate int BinaryOp(int x, int y);
public class SimpleMath
{
public static int Add(int x, int y)
{
int ans = x + y;
Console.WriteLine("{0} + {1} = {2}", x, y, ans);
return ans;
}
public static int Subtract(int x, int y)
{
int ans = x - y;
Console.WriteLine("{0} - {1} = {2}", x, y, ans);
return ans;
}
}
static void Main(string[] args)
{
BinaryOp bOP = new BinaryOp(SimpleMath.Add);
bOP += SimpleMath.Subtract;
bOP(10, 5);
Console.WriteLine();
foreach (Delegate del in bOP.GetInvocationList())
{
Console.WriteLine(del.Method.ToString());
}
Console.WriteLine();
BinaryOp bOPnew = new BinaryOp(SimpleMath.Subtract);
bOPnew += SimpleMath.Add;
foreach (Delegate del in bOPnew.GetInvocationList())
{
Console.WriteLine(del.Method.ToString());
}
Console.WriteLine();
bOPnew(7, 3);
Console.WriteLine();
Console.WriteLine(bOP == bOPnew);
bOP -= SimpleMath.Add;
bOPnew -= SimpleMath.Add;
Console.WriteLine(bOP == bOPnew);
}
}
输出:
10 + 5 = 15
10 - 5 = 5
Int32 Add(Int32, Int32)
Int32 Subtract(Int32, Int32)
Int32 Subtract(Int32, Int32)
Int32 Add(Int32, Int32)
7 - 3 = 4
7 + 3 = 10
False
True