委托和事件的综合总结

来源:百度文库 编辑:神马文学网 时间:2024/04/27 18:09:02
函数指针
一个通常的函数调用的例子:
//自行包含头文件
void MyFun(int x);    //此处的申明也可写成:void MyFun( int );
就象某一数据变量的内存地址可以存储在相应的指针变量中一样,函数的首地址也以存储在某个函数指针变量里的。这样,我就可以通过这个函数指针变量来调用所指向的函数了。
在C系列语言中,任何一个变量,总是要先申明,之后才能使用的。那么,函数指针变量也应该要先申明吧?那又是如何来申明呢?以上面的例子为例,我来申明一个可以指向MyFun函数的函数指针变量FunP。下面就是申明FunP变量的方法:
void (*FunP)(int) ;   //也可写成void (*FunP)(int x);
你看,整个函数指针变量的申明格式如同函数MyFun的申明处一样,只不过——我们把MyFun改成(*FunP)而已,这样就有了一个能指向MyFun函数的指针FunP了。(当然,这个FunP指针变量也可以指向所有其它具有相同参数及返回值的函数了。
其实,MyFun的函数名与FunP函数指针都是一样的,即都是函数指针。MyFun函数名是一个函数指针常量,而FunP是一个函数数指针变量,这是它们的关系。
参考:彻底搞定C指针-函数名与函数指针
委托
委托是C#中的一种引用类型,类似于C/C++中的函数指针,与函数指针不同的是,委托面向对象,类型安全的,它是一个代表方法的对象。而且委托可以引用静态方法和实例方法,而函数指针只能引用静态方法,委托主要用于.NET框架下的事件处理程序和回调函数,一个委托可以看作是一个特殊的类,可以与常规的类放在相同的位置。与其他函数一样,必须先定义,再实例化。委托派生于System.Delegate,不过委托的定义和常规类的处理定义方法不太一样,它是通过关键字delegate来定义的。
Delegate和C++中的函数指针很像,但如果深入对比,发现其实还是有区别的,区别主要有三个方面(参考Stanley B. Lippman的一篇文章)
1) 一个 delegate对象一次可以搭载多个方法(methods),而不是一次一个。当我们唤起一个搭载了多个方法(methods)的delegate,所有方法以其“被搭载到delegate对象的顺序”被依次唤起。
2) 一个delegate对象所搭载的方法(methods)并不需要属于同一个类别。一个delegate对象所搭载的所有方法(methods)必须具有相同的原型和形式。然而,这些方法(methods)可以即有static也有non-static,可以由一个或多个不同类别的成员组成。
3) 一个delegate type的声明在本质上是创建了一个新的subtype instance,该 subtype 派生自 .NET library framework 的 abstract base classes Delegate 或 MulticastDelegate,它们提供一组public methods用以询访delegate对象或其搭载的方法(methods) ,与函数指针不同,委托是面向对象、类型安全并且安全的。
委托和事件
事件能做的,委托完全可以做到,参看MaskedTextBoxSample。比如有如下两个变量:
//使用事件
public event EventHandler eceee;
//使用委托
public EventHandler eeeeHandler;
先用Reflector查看:

我们发现,多了一个private的eceee,

再用ildasm查看IL代码:


我们发现,委托相当于class 里面的field,访问级别是public,而事件,则相当于属性,有一个private的field;正因为这样:
1.event不允许在声明它的class之外(即使是子类)被调用(除此之外只能用于+=或-=),而plain delegate则允许。
2. event不允许使用赋值运算符,而plain delegate则允许。 注意,对plain delegate,使用赋值运算符意味着进行了一次替换操作!
可能很多人都会奇怪,为什么会这样。这和现实中的概念有一定的联系。delegate就是一种类型,而event是一个对象用来通知别的对象自己发生了某种事情(也就是表达对象事件里“事件”这一概念)。注意,在现实世界里,“事件”也只能由其所有者来触发。就好比我现在很疲劳,如果我不说(触发),那别人就不知道(我们假设疲劳不会有其他外在表现)。另一方面,由于是“我现在很疲劳”,显然如果由第三者来说(触发)的话,就很难具有真实性。注意,我们前面假定了疲劳不会有其他外在表现,否则你可以说疲劳完全可以通过情绪、工作状态等等来证实:)。也就是说,“我现在很疲劳”这个“事件”只能由我自己来触发才是真实和可靠的。
这样回过头来,我们就容易理解为什么event在声明它的Class之外只允许+=和-=操作。
那为什么event还不允许使用赋值操作呢?同样对于“我现在很疲劳”,我老板获知次消息后,可能会给我放假(遇到个好老板,哈哈);我lp可能会给我煲汤……显然你也不会同意这样的事情:如果老板给我放了假,回家后lp一给我煲汤,老板放假的事情就自动取消了!
另外还有一个问题,规范的event都是如下格式:
xxxEventHandler(object sender, xxxEventArgs e);
为什么会有个sender呢?还是“我现在很疲劳”,我们把我看成员工类的一个实例,而老板处理员工疲劳事件的方法是固定的,这样“我”疲劳了,老板放我的假,张三疲劳了,老板放张三的假……为了区分是谁疲劳,就需要一个sender来标识了。
从这个意义上来讲,我开始说event更加面向对象化也不算错误,不知Cavingdeep同意否:)。
结论:
1.event更面向对象一些。
2.当我们需要灵活时,直接使用plain delegate;反之,需要严格的控制时,使用event。
3.由于event不能使用赋值运算符,因此有时我们要求一个事件在任何时刻只能有一个响应方法时,我们使用plain delegate更为方便。
4.其实event就是一个限制版的delegate,这样做是为了适应“事件”这个概念。所以你的结论是不正确的,没有event要更面向对象这一说,这与面向对象没有任何关系。简单的原则就是该使用事件的时候使用event,不需要事件这样的概念的时候就可以使用普通的delegate。
http://www.cnblogs.com/hyddd/archive/2009/07/26/1531538.html