引自:http://www.csharpwin.com/csharpspace/2793.shtml
前些天狠狠心咬咬牙,从刚发的工资中拿出几十块大洋,又给老外投资了一笔,呵呵,还好投资方向没错,物超所值啊拥有了一本Jeffrey Richter前辈的<Microsoft .net框架程序设计>,现在已经看完前17章了,可谓是进展神速啊(小小滴自夸一下)
昨天和今天两天好好的把"委托"机制研究了一下,算是小有所明白了,想起来前些天看"事件"的时候,因为其中也涉及到了委托机制,所以都看得有些云里雾里的
第一遍看的时候,大多数地方都还看得明白,但是有个地方就一直没转过来.
书上说的是,定义了一个类以后,例如书中的例子是class
MailManger(注意:该MailManger类之内还有一个描述mail消息的class
MailMsgEventArgs,也就是用来定义保存mail消息的东东,同时也是一个继承自EventArgs的类型,这是根据.net框架约定
的),这里,先贴一下它的代码
public class MailMsgEventArgs:EventArgs
2{
3public MailMsgEventArgs(String from,String to,String subject,String body)
4{
5this.from=from;
6this.to=to;
7this.subject=subject;
8this.body=body;
9}
10public readonly String from,to,subject,body;
11}
很明显,是一个用来描述的类型,具体没有多少内容,
然后,紧跟着又定义了一个委托,已经用这个委托类型(这里要插一句的是,我看完第十七章才知道委托在.net框架内部就是一个类型,所以才可以定义它的一个对象)来定义了一个事件对象(我现在的看法是,该事件对象也就是相当于一个class的对象)
delegate
void MailMsgEventHandler(Object sender,MailMsgEventArgs args);
2
3public event MailMsgEventArgs MailMsg;
//should be ‘public event MailMsgEventHandler MailMsg;‘ sorry:)
其中有一些定义事件委托的代码规范是要注意一下的.
到这里就开始有点迷糊了,为什么就一定要这样用个委托转个弯来定义一个事件呢??
然后后文就开始谈到说,定义事件的这个类(在这里是MailManger)允许其他类的对象(书中的例子是Fax和Printer)登记该事件,然后在有
特定事件发生时(也就是这里的MailMsg事件),由事件宿主MailManger来通知它的事件登记者,告诉它们采取措施,例如Fax就应该立即
fax一份传真出来,打印机也就得老老实实的打印东东出来(嗯,看来这个事件机制真的很牛
)
在后文中,就具体说明了MailMsg的工作机制,原来是C#编译器看到有这么一句以后,就把它翻译成三个构造,如下:
private MailMsgEventHandler MailMsg=null;
2//我认为这里就是关键了,也就是指定了委托对象的头指针
3
4[MethodImplAttribute(MethodImplOptions.Synchronized)]
5public virtual void add_MailMsg(MailMsgEventHandler handler)
6{
7MailMsg=(MailMsgEventHandler)Delegate.Combine(MailMsg,handler);
8}
9
10[MethodImpl(MethodImplOptions.Synchronized)]
11public virtual void remove_MailMsg(MailMsgEventaHandler handler)
12{
13MailMsg=(MailMsgEventHandler)Delegate.Remove(MailMsg,handler);
14}
仔细看了委托那一章的后几节才明白,实际上委托都是继承自MultiDelegate类型,而MultiDelegate又继承自Delegate类型,
而Delegate类型定义了两个方法(这里的virtual是不应该有的),其中的add方法就是把委托对象添加到委托链上,而remove方法则是把
委托对象从委托链上移出,没看委托一章时,虽然大致上明白这里两个方法的含义,但是不明白它们的真正内涵之所在.
前思后想,终于明白其中的真谛之所在,由于Delegate的机制,add了一个委托对象以后,就相当于在这个委托链上增加了一个委托对象,remove
了一个委托对象以后,就相当于在这个委托链上移出了一个委托对象,可以把这里的委托链理解为数据结构中的链表(我就是这么理解的),要对该委托链表进行操
作,只需要找到链表的尾巴(这里是tail,而不是head,可以从Delegate的重载方法中看出),然后依次进行操作.直到该委托链上的所有对象都
有操作完毕.
最开始一直不理解的是:因为虽然在Fax类型中确实把自身登记到该事件中去了,但是这个事件宿主是怎么知道都有谁已经登记了呢?如果不知道都有哪个对象已经登记了该事件,那又怎么去轮个通知呢?
看完了之后,才总算了解了委托的伟大之所在.
其实我认为最明白的想法就是,由事件宿主来维护一个委托对象(也就是它自己定义的事件,这里必须是一个委托对象),并且同时有该委托类型的一个对象(这里
肯定是一个引用对象),在事件登记者都已经操作完毕之后,也就是把自己添加到该委托对象的屁屁后面以后,该事件宿主只需要通知一个人,也就是它自己维护的
那个委托对象,因为是指针形式,就会自动也把自己屁屁后面的跟屁虫挨个都通知到,这样就达到了通知所有事件登记者的目的。