漫话CLR ---- 委托

  委托,delegate,说白了也就是个语法糖.没有他我们可以写程序,有了他我们可以写出更好的程序.

delegate void Feedback(int value);

  方法签名之前前加上 delegate 关键字,我们就定义了一个最简单的委托.但,事实上编译器为我们做了另一件事:创建委托类.人肉解压缩一下:

//这里就是整个委托最为核心的内容,委托 = 封装了的类 + Invoke方法
class
Feedback : System.MulticastDelegate { public Feedback(Object obj,IntPtr method); public virtual void Invoke(int value); public virtual IAsyncResult BeginInvoke(int value, AsyncCallback callback,Object obj); public virtual void EndInvoke(IAsyncResult result); }

  注意生成的 Invoke 方法,这个方法的和原来使用 delegate 创建的 方法签名 原型是一致的. 可以说 委托 并不是一种新的操作或者行为之类的.他只是简化了以前我们需要通过手动编码的复杂程度.原来需要编写一个类来进行操作的步骤,现在由编译器帮我们完成了,这个就是语法糖,这个就是委托.

  多播委托,或者委托链,这个是什么,其实就是在 编译器 创建的 Feedback 类中加入的一个数组,如果有多个委托方法连接到一个委托上,执行的时候就相当于 Foreach 这个数组,每个方法 执行一下他的 Invoke. 这个数组放在哪里,其实就在继承的 System.MulticastDelegate 中,他有一个私有成员变量, _invocationList,这是个数组,每次增加或者删除一个委托就是在进行维护这个 委托 数组的操作.

//多播委托的 Invoke 方法执行类似下面的伪代码
public void Invoke(int value)
{
    Delegate[] delegateSet = _invocationList as Delegate[];
    if(delegateSet != null)
    {
        // 委托数组不为null,证明是一个委托链
        foreach(Feedback d in delegateSet)
            d(value);    //或者 d.Invoke(value)
    }
    else
    {
        //不为空,则调用原始的回调方法
        _methodPtr.Invoke(_target, value);
        //逻辑近似实际代码,但实际发生的事情 C# 是表示不出来的
    }
}

  另:可以通过 GetInvocationList()方法来获取多播委托绑定的成员.

  泛型委托,就是系统中的 Action 和 Func,你可以在MSCorLib.dll 和 System.Core.dll 中找到他们,建议使用这些委托类型而不是定义更多的类型.

public delegate void Action();
public delegate void Action<T>(T obj);
public delegate void Action<T1, T2>(T1 arg1, T2 arg2);
public delegate void Action<T1, T2, T3>(T1 arg1, T2 arg2,T3 arg3);
...

public delegate TResult Func<TResult>();
public delegate TResult Func<T,TResult>(T obj);
public delegate TResult Func<T1, T2, TResult>(T1 arg1, T2 arg2);
public delegate TResult Func<T1, T2, T3, TResult>(T1 arg1, T2 arg2,T3 arg3);
...

  C#为委托提供了很多简化的语法,比如委托连的 += 和 -= 操作实际上是Delegate类中 Combine 和 Remove 方法的简化, lambda 表达式实际上是匿名方法的一种简化,匿名方法实际上在编译的时候由编译器自己生成了一个方法 ... 这些简化很有效的提高了我们的开发效率,但也让一部分开发者感到迷茫.就如一句话所说:知道真相使你自由.明白其中的原理也会让你更合理的使用这些语法糖,而不至于迷失在糖罐中.

  简化语法1: 不需要构造委托对象

button1.Click += new EventHandler(button1_Click);
//可以简化为
button1.Click += button1_Click;

  实际上,第二种情况下在编译的时候会由编译器自行加上包装器.

  简化语法2: 不需要定义回调方法

  可以理解为lambda 表达式和匿名函数,编译的时候也是由编译器"解压"为正常的方法和类.

  简化语法3: 局部变量不需要手动包装到类中即可传给回调方法

Jeffrey Richter的一个小规则:如果需要在回调的方法中包含3行以上的代码,就不使用 lambda表达式.

  委托和反射,两个重要的方法:

Delegate del = Delegate.CreateDelegate(...);
del.DynamicInvoke(...)  //伪代码,不多解释,只是说明方法名和所在的位置
原文地址:https://www.cnblogs.com/woodywu/p/3216677.html