首先多谢网上的大牛们无私地分享自己的经验,让我这样的小鸟能站在巨人的肩膀上不断前进!
参考网址:http://www.knowsky.com/395937.html(参考1)
http://hi.baidu.com/zhangguilin/blog/item/9d34dc17a088ff0ac83d6d08.html(参考2)
http://www.chinaz.com/program/2009/1014/94676.shtml(参考3)
以下是我的总结:
委托
msdn把委托描述为面向对象、类型安全、可实现多播的函数指针。
1、面向对象:.net把委托(函数指针)定义为类型,具体的类名为委托名称,并且存在继承关系:自定义委托<--System.MulticastDelegate<--System.Delegate。
2、类型安全:委托对象中有_target、_methodPtr、_methodPtrAux三个变量。当委托实例指向某个实例方法时,_target指向实例对象,_methodPtr指向实例方法的JIT STUB(如果经过了JIT编译,就直接指向实例方法的内存地址),_methodPtAux为0;当委托实例指向某个静态方法时,_target指向委托实例本身,_methodPtr指向STUB(一小段代码,用于让CLR把_target设为null),_methodPtAux指向静态方法的内存地址。从上面可以看出委托实例中不仅保存了函数的地址,还保存了函数所在类的实例,相反看一下C++的函数指针只是保存函数的地址,而不管实例函数属于哪一个类。
3、可实现多播:通过+=、—=添加(移除)函数指针。实例化委托时,MyDelegate d = new MyDelegate(my)为单播形式;MyDelegate d += new MyDelegate(my),d += new MyDelegate(my1)为多播形式。添加(移除)函数指针实际调用了MulticastDelegate的CombineImpl方法把函数指针添加到_invocationList(类型为object数组),可以同过委托实例.GetInvocationList()方法获取。
注意:在多播情况,假如某些函数有返回值,那么要使用下列方式来获取返回值。
foreach(var item in 委托实例.GetInvocationList())
{
item();
}
并非像(参考2)里面说的多播中的函数不能有返回值。
事件
事件跟委托有许多相似之处,经常不知道使用哪一个,这里着重说明两者的区别。这里参考了.NET委托: 一个C#睡前故事,这个例子描述得十分清楚。
下面是自己的总结。
委托对象定义为public后不仅所属类内部能调用,类外部也能调用;事件不管即使定义为public,也只能在所属类的内部触发,而类外部只能订阅不能触发事件。
总结
使用事件可以降低耦合度,事件的触发与事件的订阅分离,让感兴趣的对象订阅某个对象的全部或部分事件。