引自:
前些天狠狠心咬咬牙,从刚发的工资中拿出几十块大洋,又给老外投资了一笔,呵呵,还好投资方向没错,物超所值啊拥有了一本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);23public 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} 910[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类型中确实把自身登记到该事件中去了,但是这个事件宿主是怎么知道都有谁已经登记了呢?如果不知道都有哪个对象已经登记了该事件,那又怎么去轮个通知呢? 看完了之后,才总算了解了委托的伟大之所在. 其实我认为最明白的想法就是,由事件宿主来维护一个委托对象(也就是它自己定义的事件,这里必须是一个委托对象),并且同时有该委托类型的一个对象(这里 肯定是一个引用对象),在事件登记者都已经操作完毕之后,也就是把自己添加到该委托对象的屁屁后面以后,该事件宿主只需要通知一个人,也就是它自己维护的 那个委托对象,因为是指针形式,就会自动也把自己屁屁后面的跟屁虫挨个都通知到,这样就达到了通知所有事件登记者的目的。