.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()); } }
相关文章推荐
- ASP.NET的事件模型
- [转]对.NET Framework "事件"机制理解的代码分析
- ASP.NET用户控件事件的定义和实践-- 自定义事件数据类
- ADO.NET Entity Framework将概念模型映射到存储架构
- RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.2->Web版本新增新的角色授权管理界面效率更高、更规范
- 模型设计与实践---(六)重叠IO,事件通知(Overlap Event)
- ADO.NET Entity Framework 定义高级数据模型(实体框架任务)
- .NET Framework 加密模型
- 仿net事件委托的java事件模型实现
- .Net Framework中的委托与事件
- .Net中的事件(Event)编程模型
- 《Pro ASP.NET MVC 3 Framework》学习笔记之三十一 【模型验证】(转)
- 《Pro ASP.NET MVC 3 Framework》学习笔记之二【领域模型的概念介绍及MVC模型绑定】
- ASP.NET用户控件事件的定义和实践
- ASP.NET的事件模型
- ADO.NET Entity Framework生成 School 实体数据模型(实体框架快速入门)
- ADO.NET Entity Framework CSDL、SSDL 和 MSL 规范
- ADO.NET Entity Framework 如何:使用存储过程定义模型(实体框架)
- ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第三章:搜索、高级过滤和视图模型
- 《Pro ASP.NET MVC 3 Framework》学习笔记之四【领域模型介绍】