==============
@ 在类中定义事件
==============
using
System;
// Mail 管理。
class MailManager{
// 1.定义事件参数,用于向事件接受者传递附加信息。
// 事件参数类都应该继承自 System.EventArgs,并且类型名称以 EventArgs 结束。
public class MailMsgEventArgs : EventArgs{
public MailMsgEventArgs( string from, string to, string subject, string body) {
this .from = from; // 发送者。
this .to = to; // 接受者。
this .subject = subject; // 主题。
this .body = body; // 正文。
}
public readonly string from, to, subject, body;
}
// 2.定义一个委托类型,用于指定事件触发时被调用的方法原型。
// 委托类型的名称应该以 EventHandler 结束。另外方法原型返回值应该为 void,并且有两个参数:
// 第一个参数指向发送通知的对象,第二个是事件参数。如果我们定义的时间没有需要传递给事件接受者
// 的附加信息,就不需要定义新的委托类型,直接使用 System.EventHandler,并将 EventArgs.Empty
// 传递给第二个参数即可。
public delegate void MailMsgEventHandler(Object sender, MailMsgEventArgs args);
// 3.定义事件。
// 如下定义的事件的名称是 MailMsg,类型为 MailMsgEventHandler,其含义为所有事件接受者都必须提供
// 一个原型和 MailMsgEventHandler 想匹配的方法。
public event MailMsgEventHandler MailMsg;
// 4. 触发事件。将一些外部输入转化为触发事件的动作。
public void SimulateArrivingMsg( string from, string to, string subject, string body) {
MailMsgEventArgs e = new MailMsgEventArgs(from, to, subject, body);
// 调用虚方法通知对象事件已发生,如果派生类型没有重写该虚方法,
// 对象将通知所有登记的时间侦听者。
OnMailMsg(e);
}
// 5.事件处理,负责通知事件的侦听者。
protected virtual void OnMailMsg(MailMsgEventArgs e) {
if (MailMsg != null ) {
// 将事件通知给委托链表上的所有对象。
MailMsg( this , e);
}
}
}
// Mail 管理。
class MailManager{
// 1.定义事件参数,用于向事件接受者传递附加信息。
// 事件参数类都应该继承自 System.EventArgs,并且类型名称以 EventArgs 结束。
public class MailMsgEventArgs : EventArgs{
public MailMsgEventArgs( string from, string to, string subject, string body) {
this .from = from; // 发送者。
this .to = to; // 接受者。
this .subject = subject; // 主题。
this .body = body; // 正文。
}
public readonly string from, to, subject, body;
}
// 2.定义一个委托类型,用于指定事件触发时被调用的方法原型。
// 委托类型的名称应该以 EventHandler 结束。另外方法原型返回值应该为 void,并且有两个参数:
// 第一个参数指向发送通知的对象,第二个是事件参数。如果我们定义的时间没有需要传递给事件接受者
// 的附加信息,就不需要定义新的委托类型,直接使用 System.EventHandler,并将 EventArgs.Empty
// 传递给第二个参数即可。
public delegate void MailMsgEventHandler(Object sender, MailMsgEventArgs args);
// 3.定义事件。
// 如下定义的事件的名称是 MailMsg,类型为 MailMsgEventHandler,其含义为所有事件接受者都必须提供
// 一个原型和 MailMsgEventHandler 想匹配的方法。
public event MailMsgEventHandler MailMsg;
// 4. 触发事件。将一些外部输入转化为触发事件的动作。
public void SimulateArrivingMsg( string from, string to, string subject, string body) {
MailMsgEventArgs e = new MailMsgEventArgs(from, to, subject, body);
// 调用虚方法通知对象事件已发生,如果派生类型没有重写该虚方法,
// 对象将通知所有登记的时间侦听者。
OnMailMsg(e);
}
// 5.事件处理,负责通知事件的侦听者。
protected virtual void OnMailMsg(MailMsgEventArgs e) {
if (MailMsg != null ) {
// 将事件通知给委托链表上的所有对象。
MailMsg( this , e);
}
}
}
======================
@ 编译器对事件定义语句的处理
======================
对于上面代码中的定义事件的语句:
public event MailMsgEventHandler MailMsg;
编译器会将其翻译为如下三个方法:
//
1. 一个初始化为 null 的"私有"委托类型字段。
private MailMsgEventHandler MailMsg = null ;
// 2. 一个允许其他对象登记事件的"公有" add_* 方法。
[MethodImplAttribute(MethodImplOptions.Synchronized)]
public void add_MailMsg(MailMsgEventHandler handler){
this .MailMsg = (MailMsgEventHandler)Delegate.Combine(MailMsg, handler);
}
// 3. 一个允许其他对象注销事件的"公有" remove_* 方法。
[MethodImplAttribute(MethodImplOptions.Sysnchronized)]
public void remove_MailMsg(MailMsgEventHandler handler){
MailMsg = (MailMsgEventHandler).Delegate.Remove(MailMsg, handler);
}
private MailMsgEventHandler MailMsg = null ;
// 2. 一个允许其他对象登记事件的"公有" add_* 方法。
[MethodImplAttribute(MethodImplOptions.Synchronized)]
public void add_MailMsg(MailMsgEventHandler handler){
this .MailMsg = (MailMsgEventHandler)Delegate.Combine(MailMsg, handler);
}
// 3. 一个允许其他对象注销事件的"公有" remove_* 方法。
[MethodImplAttribute(MethodImplOptions.Sysnchronized)]
public void remove_MailMsg(MailMsgEventHandler handler){
MailMsg = (MailMsgEventHandler).Delegate.Remove(MailMsg, handler);
}
add_* 和 remove_* 方法都应用了一个 MethodImplAttribute 特性,这些方法被标识为同步方法,使得它们得以
实现线程安全:也就是多个事件侦听者可以同时登记或者注销事件,而不损坏委托链表。这两个方法的访问限制
取决于事件的访问限制,如果事件被定义为受保护事件,那么这两个方法也将为受保护方法。
============
@ 定义侦听事件的类
============
//
传真机侦听 MailManager 的 MailMsg 事件,并发送传真(输出到控制台)。
class Fax
{
// 将 MailManager 对象传递给构造函数。
public Fax(MailManager mm) {
// 构造一个指向 FaxMsg 回调方法的 MailMsgEventHandler 委托实例,
// 然后登记 MailManager 的 MailMsg 事件。
mm.MailMsg += new MailManager.MailMsgEventHandler(FaxMsg);
}
// MailManager 将调用该方法来通知 Fax 对象收到到一个新的电子邮件消息。
// sender: 表示 MailManager 对象,如果希望和事件的触发者通信,可以使用该参数。
// e:表示 MailManager 对象提供的一些附加事件信息。
private void FaxMsg(Object sender, MailManager.MailMsgEventArgs e) {
Console.WriteLine( " From: {0} \n To: {1} \n Subject: {2} \n Body: {3} \n " +
e.from, e.to, e.subject, e.body);
}
// 注销事件。
public void Unregister(MailManager mm) {
// 创建一个新的委托实例是为了将其从委托链表中移除(参见《深入理解委托》)
MailManager.MailMsgEventHandler callback = new MailManager.MailMsgEventHandler(FaxMsg);
mm.MailMsg -= callback;
}
}
class Fax
{
// 将 MailManager 对象传递给构造函数。
public Fax(MailManager mm) {
// 构造一个指向 FaxMsg 回调方法的 MailMsgEventHandler 委托实例,
// 然后登记 MailManager 的 MailMsg 事件。
mm.MailMsg += new MailManager.MailMsgEventHandler(FaxMsg);
}
// MailManager 将调用该方法来通知 Fax 对象收到到一个新的电子邮件消息。
// sender: 表示 MailManager 对象,如果希望和事件的触发者通信,可以使用该参数。
// e:表示 MailManager 对象提供的一些附加事件信息。
private void FaxMsg(Object sender, MailManager.MailMsgEventArgs e) {
Console.WriteLine( " From: {0} \n To: {1} \n Subject: {2} \n Body: {3} \n " +
e.from, e.to, e.subject, e.body);
}
// 注销事件。
public void Unregister(MailManager mm) {
// 创建一个新的委托实例是为了将其从委托链表中移除(参见《深入理解委托》)
MailManager.MailMsgEventHandler callback = new MailManager.MailMsgEventHandler(FaxMsg);
mm.MailMsg -= callback;
}
}
========
@ 使用事件
========
using
System;
public class Test
{
public static void Main( string [] args) {
// 定义事件发送者 mm。
MailManager mm = new MailManager();
// 定义事件侦听者,侦听 mm 发送的时间。
Fax fax = new Fax(mm);
// 触发事件发送者定义的事件。
mm.SimulateArrivingMsg( " Me " , " You " , " Love " , " I love you ! " );
}
}
public class Test
{
public static void Main( string [] args) {
// 定义事件发送者 mm。
MailManager mm = new MailManager();
// 定义事件侦听者,侦听 mm 发送的时间。
Fax fax = new Fax(mm);
// 触发事件发送者定义的事件。
mm.SimulateArrivingMsg( " Me " , " You " , " Love " , " I love you ! " );
}
}
输出:
From: Me
To: You
Subject: Love
Body: I love you !