事件是实现交互的类型成员。
定义事件需要提供以下能力:
1.方法可登记/注销它对该事件的关注。
2.改事件发生时,登记了的方法会收到通知。
类型之所以能提供事件通知功能,是因为类型维护了一个已登记方法的列表。事件发生后,类型将通知列表中所有已登记的方法。
为了理解事件在CLR中的工作机制,举个实用的场景:
假定要设计一个电子邮件程序。电子邮件到达时,用户希望将该邮件转发给传真机或寻呼机。
构建这个应用程序时,假定先设计一个名为MailManager的类型,负责接收传入的电子邮件。MailManager类型公开了一个名为NewMail的事件。其他类型(如Fax和Pager)的对象可登记它们对这个事件的关注。MailManager收到信邮件时,会引发该事件,将邮件分发给每一个登记的对象。
应用程序初始化时,只实例化一个MailManager实例。然后,应用程序可实例化任意数量的Fax和Pager对象。
11.1 设计要公开事件的类型
11.1.1 第1步:定义类型来容纳所有需要发送给事件通知接收者的附加信息
事件对象想向接收通知的对象传递一些附加信息,那么需要封装到自己的类中,包含私有字段和只读公共属性。根据约定,这种类型应该从System.EventArgs类派生,并且类名以EventArgs结束。
//首先 定义类型来容纳发送给接受者的附加信息 internal class NewMailEventArgs:EventArgs{ //附加信息的私有字段 private readnoly string m_from,m_to,m_subject; //附加信息的只读属性 public string From{ get{return m_from;}} public string To{ get{return m_to;}} public string subject { get{return m_subject;}} public NewMailEventArgs(string from,string to,string subject){ m_from = from; m_to = to; m_subject = subject; } } //后续的步骤在MailManager类中进行 internal class MailManager{ }
11.1.2 第2步:定义事件成员
事件成员使用event关键字来定义。
每个事件成员要指定一下内容:
1.一个可访问性标示符(public)。
2.一个委托类型,它指出要调用的方法的原型。
3.一个名称(可以是任意有效的标示符)。
MailManager类的事件成员:
internal class MailManager{ //第2步:定义事件成员 public event EventHandler<NewMailEventArgs> NewMail; ... }
NewMail是这个事件的名称。
事件成员的类型是EventHandler<NewMailEventAgrs>,意味着“事件通知”的所有接受者都必须提供一个原型和EventHandler<NewMailEventArgs>委托类型匹配的回调方法。
由于泛型System.EventHandler委托类型的定义如下:
public delegate void EventHandler<TEventArgs>(Object sender,TEventArgs e) where TEventArgs: EventArgs;
所以方法原型必须具有以下形式:
void MethodName(Object sender,NewMailEventArgs e);