.Net中的事件(Event)编程模型
2011-10-10 10:33 elivsit 阅读(500) 评论(0) 编辑 收藏 举报事件(Event)编程是.Net平台的一大特色,也是.Net倡导的组件编程(Component Programming)的一个重要组成部分,在Windows Forms,ASP.Net,以及众多的异步编程模型中都有重要的应用,对它的深刻理解与把握是.Net平台下软件开发一个重要环节。本文将围绕几个典型的例子详细阐述.Net事件的内部机制,编程模型,为广大程序员提供.Net平台下开发时的考量与学习是的借鉴。
简单的讲,事件就是一种消息通知,它是对象之间传递消息的一种方式。我们日常生活中也有消息通知,单位科长老王打电话来说“小李,今天下午三点开项目洽谈会!”你自然会安排下午的项目洽谈会活动。当然前提是老王和你有这种消息传递的契约关系,即老王有权通知你开项目洽谈会,而你有义务接受这样的通知去开项目洽谈会。这和.Net的事件模型非常类似。.Net采用一种称作“发布——登记——接受”的逻辑来在对象之间传递消息,通知某个事件的发生,如鼠标对某个按钮的点击,电子邮件的到来等等。一个对象只有在发布某事件后才有权力在该事件到来时通知其它对象,而一个对象只有在登记某事件后才有资格在该事件发生后接受发布事件的对象的通知。注意这里发生的事件是在事件发布者对象里发生的,而这一事件又有必要让另一对象知道,这才有这样的事件模型的存在的基础和必要。
在事件模型中,事件发送者起初并不知道哪个对象来接受这样的事件。但又要通知到它,怎么办呢?老王一开始也并不知道要你开会,但它发现自从它安排了项目洽谈会后,你在上面登记过,它通过你的登记电话便找到了你。类似的,事件发送者也要这样一个“登记本”,这在.Net里通过一个称作委派(Delegate)的技术来实现的。委派是指向一个类方法的引用,很类似传统C/C++语言里的函数指针,不过函数指针只能指向一个函数句柄,而委派却可以指向多个方法(这也为事件的多播multicast提供了底层机制),同时增加了普通语言运行时(Common Language Runtime)的类型安全管理。下面是声明委派的一个例子:
public delegate void SomeEventHandler(object sender, SomeEventArgs e);
注意这里delegate是声明委派的关键字,它告诉编译器SomeEventHandler是一个委派,sender是事件发送者,而e是发生的事件的有关参数。委派仅仅给出了函数的形式的约定,而没有任何实现。实际上委派是在程序的运行时才创建的,编译时仅给出结构信息。
而一个接受事件的对象必须在它的类声明中提供处理相应事件的方法:
public class SomeReceiverClass
{
。。。//类的其他实现
public void SomeEventProcessMethod(object sender,SomeEventArgs e)
{
。。。//处理事件的方法。
}
}
而一个事件发送者的对象必须在它的类声明中提供事件声明,和相应的事件触发机制:
public class SomeSenderClass
{
。。。//类的其他实现
public event SomeEventHandler SomeEvent;//事件声明
protected virtual void OnSomeEvent(SomeEventArgs e)
{
if(SomeEvent !=null)
SomeEvent(this,e);
}
public void SomeTiggerMethod()
{
。。。//其它实现。
SomeEventArgs e=new SomeEventArgs(。。。);//实例化事件参数
OnSomeEvent(e);//触发事件。
}
}
现在事件的发布,处理方法,触发方法,发送者与接受者之间的联系——委派都建好了,只剩下我们在最后编程时登记的工作了:
public class SomeApp
{
public static Main(string[] args)
{
SomeEventReceiver myReceiver=new SomeEventReceiver();//实例化事件接受者
SomeEventReceiver mySender=new mySender();//实例化事件发送者
MySender.SomeEvent+=new
SomeEventHandler(myReceiver.SomeEventProcessMethod);//登记事件
。。。//其他一些有可能引发SomeEvent的事件的操作。
}
}
注意这里用“+=”和“-=”的符号来登记或取消登记操作。为实现多播事件,我们可以多次登记便可:
SomeEventReceiver mySender=new mySender();//实例化事件发送者
SomeEventReceiver1 myReceiver1=new SomeEventReceiver1();//实例化事件接受者
SomeEventReceiver2 myReceiver2=new SomeEventReceiver2();//实例化事件接受者 mySender.NewMailEvent+=new
NewMailEventHandler(myReceiver1. SomeEventProcessMethod );
mySender.NewMailEvent+=new
NewMailEventHandler(myReceiver2. SomeEventProcessMethod);
末了,我们给出一个完整的邮件通知程序,并加油详细注释,大家可以在这个基础上更深一步地研究.Net平台上的事件模型及其底层机制。
namespace Cornfield
{
using System;
//信邮件事件参数类
public class NewEmailEventArgs: EventArgs
{
public NewEmailEventArgs(string subject, string message)
{
this.subject = subject;
this.message = message;
}
public string Subject
{
get
{
return(subject);
}
}
public string Message
{
get
{
return(message);
}
}
string subject;
string message;
}
//新邮件委派声明
public delegate void NewMailEventHandler(object sender,NewEmailEventArgs e);
//邮件发送类声明
public class EmailSender
{
//新邮件事件声明
public event NewMailEventHandler NewMailEvent;
protected void OnNewMail(NewEmailEventArgs e)
{
if (NewMailEvent != null)
NewMailEvent(this, e);
}
//发送邮件
public void SendMail(string subject, string message)
{
NewEmailEventArgs e = new NewEmailEventArgs(subject, message);
OnNewMail(e);
}
}
//邮件接收者声明
public class EmailReceiver
{
public EmailReceiver(string name)
{
_name=name;
}
//处理收到新邮件事件的方法
public void ComeMail(object sender, NewEmailEventArgs e)
{
Console.WriteLine(“This is Receiver {0} ,receive a new email:\n{1} {2}”,_name,
e.Subject, e.Message);
}
string _name;
}
//测试类
public class Test
{
public static void Main()
{
EmailSender mySender = new EmailSender();//邮件发送者
EmailReceiver myReceiver1 = new EmailReceiver(“Receiver1″);//第一个接受者
EmailReceiver myReceiver2 = new EmailReceiver(“Receiver2″);//第二个接收者
mySender.NewMailEvent+=new
NewMailEventHandler(myReceiver1.ComeMail);//登记邮件事件
mySender.NewMailEvent+=new
NewMailEventHandler(myReceiver2.ComeMail); //登记邮件事件
mySender.SendMail(“Hello!”, “I am from Sender!!!”);//发送邮件,多播
mySender.NewMailEvent-=new
NewMailEventHandler(myReceiver2.ComeMail); //取消登记邮件事件
mySender.SendMail(“Hello!”, “I am from Sender!!!”);//再次发送邮件,单播
}
}
}
如大家所见,我们可以得到这样的输出结果:
This is Receiver Receiver1 ,receive a new email:
Hello! I am from Sender!!!
This is Receiver Receiver2 ,receive a new email:
Hello! I am from Sender!!!
This is Receiver Receiver1 ,receive a new email:
Hello! I am from Sender!!!
实际上,在以后遇到的不管是Windows Forms编程,还是ASP.Net编程,以及众多的异步操作编程,我们都会大量的接触到事件编程的模型,在这些编程中,有时系统为我们做好了发送类,接受类,委派的声明实现,只要我们登记和取消登记即可达到操纵事件的目的。而有些,尤其是涉及到系统底层的开发,往往要我们自己实现整个事件的发送,接受,委派等等诸多底层机制。只要我们掌握了.Net平台的底层事件机制和模型,遇到任何问题都是容易解决的。