1. 委托(Delegate)
委托是.net平台上处理函数指针的一种安全的机制,通过一种引用类型(Class)对函数指针进行封装,只有相同签名(相同的返回值类型、相同的参数顺序、相同的参数类型和相同的参数个数)的函数才能被初始化到对应的委托上,一种委托代表一类相同签名的函数。
函数指针在传递过程中,client程序不知道此函数的返回值和参数情况,如果正确,在运行时不会产生异常,否则在严重的情况下,会致使整个程序崩溃,函数指针的类型不安全就很显然了。委托则是类型安全,它很好地在编译时就将这类的问题处理掉。
2. 事件(Event)
事件是一种特殊的委托,提供一种方便的发布/订阅模型,开发人员不用太多关心委托的合并与分离,只需要关心事件的路由,在每个事件的后端有一个事件集合,当事件发生时,事件就会一一通知所有的事件侦听即函数。
从程序设计的角度来看,.net平台的事件其实就是观察者(Observer)模式的应用,或者说是更基础的MVC模型的应用,一个个函数就是一个个的View,当Model变化了的时候,就会发出通知,更新所有的View也即是触发一个个的函数,而.net平台的事件对于使用者来说,隐藏了Controller,使用者也用不着关心,让使用者更加敏捷,从而提高产出。
3. 示例
下面将截两个图片结合c#和IL来探讨委托和事件:
图1. c#代码
2.对应的IL
结合图1和图2可以看出:
i. 委托类型HelloDeleage
定义委托类型HelloDeleage,只需要一行c#代码,如下:
public delegate void HelloDelegate(String name);
而对应的IL却是一个很完整的类,包括BeginInvok、Invoke和EndInvoke三个函数,并继承基础类System.MultiDelegate,(这样可以很好地理解委托了),如下图:
ii. 事件HelloEventHandller
定义事件HelloEventHandller,也只需要一行c#代码,如下:
public event HelloDelegate HelloEventHandller;
而对应的IL是:
1)添加一个private的HelloDelegate类型的HelloEventHandller对象定义,如下图:
2)添加一对add_和remove_开头的函数(其实每多一个事件定义,其对应的IL就会添加一对函数),如下图:
3)事件本身定义HelloEventHandller,如下图:
由事件HelloEventHandller的IL可知,在IL中显式地把添加和移除侦听定义出来,事件集合仍隐藏在后端,包括广播也隐藏在后端。
最后,委托和事件是不同粒度的接口,提供更优的函数指针处理机制。