本文转载自微信公众号《老王Plus》,老王Plus作者老王。转载本文请联系老王Plus公众号。一、前言先简单说一下Delegate的由来。在C/C++中,有一个概念叫做函数指针。其实就是一个指向函数的内存指针。调用函数时,只需要调用函数指针即可。至于功能本身的实现,可以放在别处,也可以稍后实现。在.Net中,没有指针的概念,但是这个方法很实用,所以也保留了这个概念,形成了现在的委托Delegate。另外,在.Net中,还扩展了委托,设计了与执行回调相同的机制,允许开发者定义回调的签名和类型。当我们声明一个委托时,编译器会生成一个派生自MulticastDelegate的类。MulticastDelegate也包含了几个方法,但是因为这些方法是由CLR运行时动态生成的,所以在代码IL中是看不到的,不需要关注。委托最大的特点就是不需要强耦合。所以调用者实际上并不知道调用的是静态方法还是实例方法,也不知道调用的具体内容。举个常见的例子,UI编程中的按钮Button类。按钮类本身不知道它的OnClick事件是如何处理的,也不需要知道。因此在实践中,OnClick事件是使用委托发布的。开发者在开发过程中实现了OnClick事件处理,供UI订阅使用。这种方式就是委托与类的解耦。2.简单委托委托有一个很简单的规则,就是:要引用的方法的返回类型或参数必须与委托类型声明相匹配。听起来有点绕,那我们举个例子吧。我们有一个方法:voidPrintInfo(stringmessage);按照规则,这个方法对应的delegate方法可以写成:voidDelegate_PrintInfo(stringmessage);这样,根据规则,在使用delegate时,可以写成:Delegate_PrintInfo=PrintInfo;这样,当我们调用Delegate_PrintInfo("HelloWangPlus")时,PrintInfo("HelloWangPlus")才真正被执行。接下来,让我们看一下委托的声明。publicdelegateintDelegate_Method(intx,inty);委托可以封装任何方法。在上面的示例中,我们接受两个参数并返回一个int值。在这样的语句中,delegate是一个关键字,表明我们正在声明一个委托。其他部分和我们正常的代码方法没有区别。再举几个例子:publicdelegatevoidDemo_Func1(stringpara);publicdelegateClassADemo_Func2(ClassBpara);privatedelegateStructADemo_Func3(intpara);除delegate外,其他内容与普通方法无异。有了声明,怎么用呢?看例子:classProgram{publicdelegateintDelegate_Method(intx,inty);staticvoidMain(string[]args){Delegate_Methodhandler=SumMethod;intresult=handler(3,4);}staticintSum(intx,inty){returnx+y;}}这个是一个简单的例子。我们首先定义一个接受两个参数并返回一个int值的委托。我想让这个委托调用下面的Sum方法,所以Sum方法和委托Delegate_Method的签名(参数和返回值)是兼容的。这里要注意理解兼容的概念,不是完全一样,而是兼容。写一个稍微复杂一点的例子:publicdelegatevoidDelegate_Method(intx,inty);classExampleClass{publicvoidSum(intx,inty){Console.WriteLine(x+y);}publicvoidSub(intx,inty){Console.WriteLine(x-y);}如果第一个例子很清楚,所以这个例子不难理解。3.委托链委托链的核心维护着一个可调用的委托列表。调用列表时,将调用列表中的所有委托。同时,委托链可以使用运算符,用+组合,用-删除。参见示例:publicdelegatevoidDelegate_Method(intx,inty);classExampleClass{publicvoidSum(intx,inty){Console.WriteLine(x+y);}publicvoidSub(intx,inty){Console.WriteLine(x-y);}}classProgram{staticvoidMain(string)[]args){ExampleClassexample=newExampleClass();Delegate_Method[]delegate_list=newDelegate_Method[]{example.Sum,example.Sub};Delegate_Methoddelegate_chain=delegate_list[0]+delegate_list[1];delegate_chain(100,50);}}在此示例中,定义了一个委托数组,然后使用+运算符组合这些方法。Delegate_Methoddelegate_chain=delegate_list[0]+delegate_list[1];Delegate_Methoddelegate_chain1=delegate_chain-delegate_list[0];上面两行代码,CLR会解释为(Sum+Sub)-Sum,而只执行Sub方法。这是使用-运算符从委托链中删除委托的示例。也可以遍历委托链:publicdelegatevoidDelegate_Method(intx,inty);classExampleClass{publicvoidSum(intx,inty){Console.WriteLine(x+y);}publicvoidSub(intx,inty){Console.WriteLine(x-y);}}classProgram{staticvoidMain(string[]args){ExampleClassexample=newExampleClass();Delegate_Method[]delegate_list=newDelegate_Method[]{example.Sum,example.Sub};Delegate_Methoddelegate_chain=delegate_list[0]+delegate_list[1];Delegate[]delegates=delegate_chain.GetInvocationList();for(inti=0;i
