最近看Effective C#,看到委托(delegate)和事件(event)这部分,没看懂,于是深入了解下,下面简单记录一些个人理解。
首先来看委托,功能上来说其实就是个函数指针(原谅我既有的C++思维),只不过它提供了类型安全,可以支持各种方法(包括对象的成员方法,会自动传递对象引用本身,这点函数指针其实很容易模拟,只不过这里强制化了),以及运行时的安全性(即不会因为没有指向而报错)。这看起来像是一个封装的更加好的安全版的函数指针。另外,委托还支持多播,即一个委托可以挂接多个函数,当使用委托发起调用时,可以依次调用每个函数。从概念上说,委托是一种特殊的机制,在关键词上和class/struct是一个层次,用于创建委托的类型。
声明一个委托类型的语法格式如下:
[修饰词 public/private…] delegate [返回值类型 void/int…] [委托类型名称] ( [参数列表] );
一个声明实例:
public delegate void MyDelegate(int s);(注意是声明,不是具体对象,可以放在class外)
创建一个委托类型的实例:
MyDelegate myDelegate = new MyDelegate(someConcreteFunc);
再来看事件,事件是一种特殊的委托类型的对象。它的特殊之处有二,一是它的签名是特殊的,二是针对它的操作也是有限制的。所谓签名就是指函数原型,即固定的返回值和参数的类型。操作的限制是只能使用+=和-=操作,而不能使用赋值操作(=)。
事件的语法格式如下:
[修饰词 public/private…] event [某个已经定义过的委托类型名称] [事件名称];
一个实例:
public event MyDelegate myEvent;(注意此处是类型对象,因此必须存在于class中)
针对该事件的操作:
myEvent = new MyDelegate(somFunc1) ; ———-> 编译错误,针对事件对象,该操作不被允许,然而普通委托是可以的。
myEvent += new MyDelegate(someFunc2);
myEvent -= someFunc2;
C#中的委托和事件这两个概念让我混淆了一段时间,网上看来的资料有的也让我更难理解。我只好自己来总结,首先这两个不是同一个层次的概念,委托(这里指delegate)是与class关键字同层次的,用于创建委托类型(这里指某个具体的类型,如上文的MyDelegate);事件是一种特殊的委托类型的实例对象,事件的创建必须依赖于某个预先定义好的符合一定要求的委托类型。如上文中的myEvent。
其次我觉得不便理解的是事件这个提法,事实上定义出来的事件是个委托类型的对象,它负责调用针对该事件的所有已经挂接到该委托下的函数。所以我认为称之为eventHandler更具可读性。而针对该对象的+=/-=操作只是在增加事件响应函数的数目而已。真正的触发事件的代码,是在其它地方,而且最终也就是以委托调用的形式出现。在我的概念中,事件一直是触发出来的,所以当我看到event这个关键词,以及对应的+=和-=操作后,就更难理解了。event这个关键词可以用,不过说明的时候还是习惯地叫它事件处理委托吧,这样定义才准确,至少更便于我理解。
附一个写的比较好的博文,供以后参考:
经过实验,需作一些修正,event并不对函数签名有所限制,只是提倡程序员使用类似于(object sender, XXEventArgs e)这样的参数列表,另外,事件处理的执行不创建新的线程,属于同步操作,所以对于一些耗时较长的操作还需要辅助以多线程机制为宜。