C#事件的使用(一)

==============
@ 在类中定义事件
==============

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);
        }
    }
}

 

======================
@ 编译器对事件定义语句的处理
======================

对于上面代码中的定义事件的语句:
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);
}

 

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;
    }
}

 

========
@ 使用事件
========

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 !"); 
    }
}

输出:
 From: Me
 To: You
 Subject: Love
 Body: I love you !

 

posted @ 2008-06-29 14:54  NanKe Sir's Blog  阅读(1475)  评论(0编辑  收藏  举报