您的位置:首页 > 其它

.NET Framework事件模型规范实践

2011-05-25 12:31 344 查看

事件模型准则

下面的准则中斜体字“
Custom”

是自定义部分,请用你的实际名称来代替。

事件的名称应该采用PascalCasing
命名方式,以

Custom
Event命名。

声明事件委托时,使用void
类型返回值,

Custom
Event事件的委托是

Custom
EventHandler,事件委托接受两个参数,一个是事件源对象,另一个是事件数据,一律命名为
sender

e


定义一个提供事件数据的类,在类内部定义要传递的数据。应该从System.EventArgs
类派生该类,以

Custom
EventArgs进行命名,。即使我们确定不需要向事件处理程序发送事件数据,也应该派生一个空的事件数据类,这样做可以在以后的版本中部引入重大更改的情况下想事件添加数据。

下面是一个例子:

//事件数据类

public

class
PublisMagazineEventArgs : EventArgs
{
}

//事件委托

public

delegate

void

PublishMagazineEventHandler
(
Publisher sender
,

PublisMagazineEventArgs e
);

在引发事件的类中声明一个受保护的虚方法来触发事件。以On

Custom
Event进行命名,并接受一个事件数据类对象作为参数,命名为
e
。遵循从准则可以使派生类能够通过重写受保护的方法来处理基类事件。

触发事件永远发生在事件源类里面。

下面是个例子:

//触发事件的方法

protected

virtual

void

OnPublishMagazineEvent
(

PublisMagazineEventArgs e
)

// 在这个方法内触发事件

public

void

DoPublish
(
string
magazineName
,

string
date
)

{

//
做一些其它的事情

//触发事件

OnPublishMagazineEvent
(
new

PublisMagazineEventArgs
());

}

在事件监听者类中声明事件处理方法,以HandleCustom

Event命名,方法签名必须跟事件委托标识的签名相同。

public

void

HandlePublishMagazineEvent
(
Publisher sender
,

PublisMagazineEventArgs e
)

一些其它准则:

当引发非静态事件时,不要将 null(在 Visual Basic 中为 Nothing)作为 sender 参数进行传递。

对于静态事件,sender 参数应该为 null(在 Visual Basic 中是 Nothing)。

当引发事件时,不要将 null(在 Visual Basic 中为 Nothing)作为事件数据参数进行传递。

如果没有事件数据,则传递
Empty

,而不要传递 null。

事件处理方法中会发生任意代码执行,对此一定要做好准备。

考虑将引发事件的代码放置在 try-catch 块中,以防止由事件处理程序引发的未处理异常所导致的程序终止。

考虑引发最终用户可以取消的事件。这仅适用于事前事件。

如果您正在设计可取消的事件,请使用
CancelEventArgs

(而非
EventArgs

)作为事件数据对象 e 的基类。

一个完整例子:出版社与订阅者

下面这个简单的例子用来说明如何定义和使用事件,以及运用上面的准则。

using System;
/// <summary>
/// 事件数据类,派生自System.EventArgs
/// </summary>
public class PublisMagazineEventArgs : EventArgs
{
//订阅者不可以修改杂志的名称和出版日期,所以使用readonly
private readonly String magazineName;
private readonly String publishDate;

public string MagazineName {
get { return magazineName; }
}

public string PublishDate {
get { return publishDate; }
}

public PublisMagazineEventArgs(string name, string date)
{
magazineName = name;
publishDate = date;
}

}
/// <summary>
/// 出版社类
/// </summary>
class Publisher
{

string publisherName;

public string PublisherName {
get { return publisherName; }
}

public Publisher(string name)
{
this.publisherName = name;
}

//声明自定义的事件委托类型,使用CustomEventHandler命名,必须带俩个参数
//其中第二个参数是派生自System.EventArgs类的存放事件数据的类
public delegate void PublishMagazineEventHandler(Publisher sender, PublisMagazineEventArgs e);
//声明事件,使用CustomEvent命名
public event PublishMagazineEventHandler PublishMagazineEvent;

//使用受保护的虚方法来触发事件
protected virtual void OnPublishMagazineEvent(PublisMagazineEventArgs e)
{
//声明一个该事件的一个副本,以避免在检查空值之后触发事件之前,
//有订阅者退订了杂志而引起的对事件对象的竞争情况
PublishMagazineEventHandler handler = PublishMagazineEvent;
if (handler != null) {
handler(this, e);
}
}

///订阅杂志
public void SubscribeMagazine(Subscriber sub)
{
PublishMagazineEvent += sub.HandlePublishMagazineEvent;
}

///取消订阅杂志
public void UnsubscribeMagazine(Subscriber sub)
{
PublishMagazineEvent -= sub.HandlePublishMagazineEvent;
}

///发布杂志,同时触发事件
public void DoPublish(string magazineName, string date)
{
Console.WriteLine("杂志《{0}》已于{1}出版发行", magazineName, date);
//触发事件,通知订阅者
OnPublishMagazineEvent(new PublisMagazineEventArgs(magazineName, date));
}

}
class Subscriber
{
private string name;
public Subscriber(string name)
{
this.name = name;
}
//声明事件处理方法,注意该方法的方法签名必须与事件委托声明的方法签名相同
///订阅事件处理方法
public void HandlePublishMagazineEvent(Publisher  sender, PublisMagazineEventArgs e)
{
Console.WriteLine(name + "已从“{0}”收到杂志: 《{1}》", sender.PublisherName, e.MagazineName);
}
}
class TestDriver
{
public static void Main()
{
Publisher pub1 = new Publisher("电脑世界出版社");
//实例化一些订阅者
Subscriber zs = new Subscriber("张山");
Subscriber ls = new Subscriber("李四");
Subscriber ww = new Subscriber("王武");
//订阅杂志
pub1.SubscribeMagazine(zs);
pub1.SubscribeMagazine(ls);
pub1.SubscribeMagazine(ww);
//出版社发行杂志
pub1.DoPublish("电脑世界", Convert.ToDateTime("2010-5-25").ToString());

Console.WriteLine();
Publisher pub2 = new Publisher("时代生活出版社");
//张山、李四、王武又订阅了这个出版社的杂志
pub2.SubscribeMagazine(zs);
pub2.SubscribeMagazine(ls);
pub2.SubscribeMagazine(ww);
//出版社发行杂志
pub2.DoPublish("生活", Convert.ToDateTime("2010-5-25").ToString());

Console.WriteLine();
Console.WriteLine("一年以后...");
//一年以后,张山取消了订阅
pub1.UnsubscribeMagazine(zs);
//出版社继续发行杂志
pub1.DoPublish("电脑世界", Convert.ToDateTime("2011-5-25").ToString());
pub2.DoPublish("生活", Convert.ToDateTime("2011-5-25").ToString());
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: