论C#中的委托与事件
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
论C#中的委托与事件
在C#里,委托与事件类是两个不易理解的概念。主要阐述对委托与事件的理解,同时结合Observer设计模式与.NET Framework规范,针对生活中的案例来辨析委托与事件的应用。
标签:委托;事件Observer设计模式;.NET Framework
C#中的委托类似于C++中的函数指针,功能却更多。事件是在委托的基础上的一种结构,类似于委托的变量,在界面的控件中处处都有应用。
1 什么是委托
委托的申明格式:修饰符delegate 返回值数据类型委托名(形参列表)。
例如:Delegate int AbcDel(string s, bool b);是一个委托申明,每一个委托都有自己的签名,就是说AbcDel这个委托有string 和bool类型的形参,返回一个int类型数据,即具有这样的函数签名。委托类似于函数指针,它能够引用函数,通过传递地址的机制完成。委托是一个类,当对它实例化时,要提供一个引用函数,将其作为它构造函数的参数。例如:private int AbcFun (string str, bool bln){},则可以把这个函数传给AbcDel的构造函数,因为它们签名一致。AbcDel sd = new SomeDelegate(AbcFun),sd 引用了AbcFun,也就是说,AbcFun已被sd所登记注册,如果你调用sd,AbcFun这个函数即会被调用。
2 事件的理解
事件的申明格式:修饰符event 委托名事件名;
例如:public event AbcDel Boil;//AbcDel为委托名
Boil事件的声明与之前委托变量sd的声明唯一的区别是多了event关键字。声明事件类似于声明一个委托类型的变量。
3 Observer设计模式
假设热水器系统由两部分组成:热水器、警报器,由不同厂商进行了组装。热水器仅负责烧水;警报器在水烧开时发出警报,当水温超过95度,就发出警报。我们需要应用委托与事件来模拟此过程。
Observer设计模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖于它的对象会被自动告知并更新。Observer模式是一种松耦合的设计模式。它包括两类对象:
Subject:监视对象,它包含其他对象感兴趣的内容。热水器是一个监视对象,它包含temprature字段,当它>95时,会不断把数据发给监视它的对象。
Observer:监视者,它监视Subject,当Subject中的某件事发生时,会告知Observer,Observer即采取相应行动。Observer就是警报器。
在本例中,事情发生的顺序如下:
警报器告诉热水器,它对它的温度感兴趣(注册)。
热水器知道后保留对警报器的引用。
热水器进行烧水这一动作,当水温超过95度时,通过对警报器的引用,自动调用警报器的MakeAlert()方法。代码如下:
Heater类:
private int temperature;
public delegate void BoilHandler(int param);//声明委托
public event BoilHandler BoilEvent; //声明事件
public void BoilWater() { for (int i = 0; i 95) {if (BoilEvent != null) {//如果有对象注册
BoilEvent(temperature) ;} } }//调用所有注册对象的方法
Alarm类:public void MakeA lert(int param) {//…输出水温}
主函数主要代码如下:
heater.BoilEvent += alarm.MakeAlert;//注册方法
heater.BoilWater();//烧水,会自动调用注册过的方法
输出:Alarm:嘀嘀嘀,水已经96度了:
Alarm:嘀嘀嘀,水已经97度了:// ...
4 Net Framework中的委托与事件
上面的代码很好地完成了工作,但.Net Framework中事件模型有所不同,.Net Framework的编码规范如下:
(1)委托类型名称都以EventHandler结束;
(2)委托的原型定义:返回值void,接受两个输入参数:一个Object 类型,一个EventArgs类型(或继承自EventArgs,但类型名要以EventArgs结尾);
(3)事件的命名:委托去掉EventHandler之后剩余的部分。
委托声明原型中的Object类型的参数代表了Subject,即监视对象,在本例中是Heater。回调函数(Alarm的MakeAlert)可以通过它访问触发事件的对象(Heater)。EventArgs对象包含了Observer感兴趣的数据,即temperature。
上面这些不仅是为了编码规范,也使程序更灵活。将热水器的引用传给警报器的方法,就可以直接访问热水器的温度、型号等。按.Net Framework改写此例:
Heater类代码如下:
public string type = “RealFire 001”;//型号
public delegate void BoiledEventHandler(Object sender, BoliedEventArgs e);
public event BoiledEventHandler Boiled;
public class BoliedEventArgs : EventArgs { //定义BoliedEventArgs类,
public readonly int temperature;//传递给observer所感兴趣的信息
public BoliedEventArgs(int temperature) {this.temperature = temperature; }}
protected virtual void OnBolied(BoliedEventArgs e) {
if (Boiled != null) { Boiled(this, e); // 调用所有注册对象的方法} }
public void BoilWater() {
for (int i = 0; i 95) {
BoliedEventArgs e = newBoliedEventArgs(temperature);OnBolied(e); }}}
Alarm类代码如下:
public void MakeAlert(Object sender, Heater.BoliedEventArgs e) {
Heater ht = (Heater)sender;Console.WriteLine(“Alarm:{0},嘀嘀嘀,水已经{1}度