CLR Via C# 3rd 阅读摘要 -- Chapter 11 - Events

Designing a Type That Exposes an Event

Step #1:定义一个类型用来持有将要发送给事件通知接受者的额外信息。从System.EventArgs继承,EventArgs.Empty;

Setp #2:定义一个事件成员;

public event EventHandler<NewMailEventArgs> NewMail; 

Step #3:定义一个方法引发事件以通知注册的对象事件以及发生;

protected virtual void OnNewMail(NewMailEventArgs e) { 

    EventHandler<NewMailEventArgs> temp = Interlocked.CompareExchange(ref NewMail, null, null);

    if (temp != null) temp(this, e); 

}  

如何线程安全的引发事件?

1. 下面这段代码的temp可能会被编译器优化掉;

EventHandler<NewMailEventArgs> temp = NewMail;

if (temp != null) temp(this, e); 

2. 下面这段代码是臆想,因为VolatileRead没有一个泛型的重载;

EventHandler<NewMailEventArgs> temp = Thread.VolatileRead(re NewMail); 

...

3.  最后一种方法就是Step #2中的那段,但是实际应用时用1.的代码也可行。总之要注意线程的竞争条件。

Step #4:定义一个方法将输入转化到期望的事件;

public void Xyz(...) {

    ... 

    NewMailEventArgs e = new NewMailEventArgs(from ,to, subject);

    OnNewMail(e); 

    ... 

How the Complier Implements an Event

1. 一个PRIVATE的初始化成null的委托字段;

private EventHandler<NewMailEventArgs> NewMail = null;

2. 一个PUBLIC的add_Xyz的方法(Xyz就是事件名字)。Delegate.Combine;

public void add_NewMail(EventHandler<NewMailEventArgs> value)

3. 一个PUBLIC的remove_Xyz的方法。Delegate.Remove;

public void remove_NewMail(EventHandler<NewMailEventArgs> value) 

注意:

  • Delegate.Remove一个从未Add过的方法时,啥也不做,并不会抛出异常啥的。
  • Delegate.Add和Remove采用Interlocked Anything模式来保证线程安全。
  • 事件成员可以定义成static和virtual的。 

Designing  a Type That Listens for an Event

1. C#要求你使用+=和-=操作符在列表中add和remove委托。如果显示的调用add和remove方法,编译器会报错:CS0571。

Explicitly Implementing an Event

1. 使用一个字典存储事件标示符(键)和委托链(值);

2. System.ComponentModel.EventHandlerList。 

本章小结

  CLR的事件模型是基于委托的,是一种特殊的委托,委托就是类型安全的回调函数。描述了如何在类型中暴露事件的步骤以及如何侦听事件,对比了如何安全的触发事件的不同方式。然后分析了编译器如何编译事件。 最后设计了一个EventSet来显示的实现事件以节约资源。

posted @ 2010-04-06 16:55  bengxia  阅读(231)  评论(0编辑  收藏  举报
无觅相关文章插件,快速提升流量