C# Delegate略析

C# Delegate略析

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

posted @ 2010-03-01 23:43  Seven.Cheng  阅读(1077)  评论(0编辑  收藏  举报