CLR via C#(13)-浅谈事件
2015-09-02 15:03
423 查看
提起事件,我们都不陌生,事件使类之间有了交互的能力。它是建立在委托基础上的。有了前面对委托的了解,相信读起事件来也不会太难了。关于事件,现成的好文章数不胜数,本不打算写了。不过问道有先后,各抒己见,也不为过。想了想,还是不偷懒了,最起码能逼自己动动手,多理解几分。
方法登记对该事件的关注;
方法注销对该事件的关注;
事件发生时,登记了的方法会收到通知,作出相应的反应。
Ps:看到这几点的时候,总会不自觉地想起观察者模式。
实现过程:
1. 定义类来包含要传递的通知内容——天气预报信息
按照约定,该类应该继承自EventArgs类,并且类名形如***EventArgs。通常该类需要定义私有字段及相应的只读公共属性。
2. 定义事件管理类——信息发布中心
首先定义事件: 要求public标识符; event关键字; 委托类型; 事件名称。
本例中委托类型为EventHandler<WeatherEventArgs>,泛型System.EventHandler的定义为:
因此,要求登记该事件的方法的形式为:
void MethodName(object sender,WeatherEventArgs e);
然后定义一个受保护的虚方法,包含一个WeatherEventArgs参数。它检查一下登记列表是否为空,如果不为空则引发委托。
最后定义一个方法,接收输入信息,并且调用上面定义的虚方法。这是向外部公开的触发事件的方法,来通知所有的已登记方法。
ILDasm.exe查看一下WeatherManager类?
虽然事件定义为Public,但是产生的相应的委托字段为private。
生成了以add_和remove_开头的事件,这两个事件分别对应System.Delegate的静态方法Combine()和Remove。这些在 委托 那一节已经提到过了。
事件定义记录项,主要包括一些标记和add,remove访问器方法,建立事件与访问器的关系。它的IL部分代码如下:
3. 定义事件接收类——短信中心、电视台天气预报
首先以电视台播报类为例:
在构造器中传入WeatherManager实例参数。其中的+=操作部分实际上是add_**方法,将委托添加到事件的列表中,完成委托的登记。
类似的定义了UnRegWeather方法来注销委托。
上面已经提到过,由于上面声明事件时委托类型为EventHandler<WeatherEventArgs>,因此登记事件的方法参数形式是固定的。也就是 void WeatherForcast(object sender,WeatherEventArgs e)。
短信中心的实现十分类似,不再赘述了,代码如下。
4. 实际调用,触发事件
我这里没有使用反射之类的,而是简单利用了Delegate的GetInvocationList()方法,它对应着委托链的信息。有更好的建议也可以提出来分享。
public void GetEventDetail()
{
Delegate[] ds = UpdateWeather.GetInvocationList();
Console.WriteLine("注册客户名单:");
for (int i = 0; i < ds.Length;i++ )
{
Console.WriteLine("第"+i+"个客户:"+ds[i].Target.ToString());
Console.WriteLine(",调用方法" + ds[i].Method);
Console.WriteLine();
}
}
修改调用
感谢 右手交易 的支持和建议。
一、 事件能干什么?
类通过维护一个已登记事件列表,当事件发生的时候可以通知已登记的方法。主要功能:方法登记对该事件的关注;
方法注销对该事件的关注;
事件发生时,登记了的方法会收到通知,作出相应的反应。
Ps:看到这几点的时候,总会不自觉地想起观察者模式。
二、 怎样定义事件?
举个简单的例子:现在有一个天气预报信息发布中心,并且有短信天气预报和电视台天气预报两个客户订阅了天气信息。当新的天气数据到达后,信息发布中心会发送通知,此时短信和电视台天气预报均可以做出相应的发布。实现过程:
1. 定义类来包含要传递的通知内容——天气预报信息
按照约定,该类应该继承自EventArgs类,并且类名形如***EventArgs。通常该类需要定义私有字段及相应的只读公共属性。
2. 定义事件管理类——信息发布中心
首先定义事件: 要求public标识符; event关键字; 委托类型; 事件名称。
本例中委托类型为EventHandler<WeatherEventArgs>,泛型System.EventHandler的定义为:
因此,要求登记该事件的方法的形式为:
void MethodName(object sender,WeatherEventArgs e);
然后定义一个受保护的虚方法,包含一个WeatherEventArgs参数。它检查一下登记列表是否为空,如果不为空则引发委托。
最后定义一个方法,接收输入信息,并且调用上面定义的虚方法。这是向外部公开的触发事件的方法,来通知所有的已登记方法。
ILDasm.exe查看一下WeatherManager类?
虽然事件定义为Public,但是产生的相应的委托字段为private。
生成了以add_和remove_开头的事件,这两个事件分别对应System.Delegate的静态方法Combine()和Remove。这些在 委托 那一节已经提到过了。
事件定义记录项,主要包括一些标记和add,remove访问器方法,建立事件与访问器的关系。它的IL部分代码如下:
3. 定义事件接收类——短信中心、电视台天气预报
首先以电视台播报类为例:
在构造器中传入WeatherManager实例参数。其中的+=操作部分实际上是add_**方法,将委托添加到事件的列表中,完成委托的登记。
类似的定义了UnRegWeather方法来注销委托。
上面已经提到过,由于上面声明事件时委托类型为EventHandler<WeatherEventArgs>,因此登记事件的方法参数形式是固定的。也就是 void WeatherForcast(object sender,WeatherEventArgs e)。
短信中心的实现十分类似,不再赘述了,代码如下。
4. 实际调用,触发事件
5.番外篇——查看注册客户
现在我们再添加一个功能:查看订阅天气信息的客户,以及他们要触发的方法。我这里没有使用反射之类的,而是简单利用了Delegate的GetInvocationList()方法,它对应着委托链的信息。有更好的建议也可以提出来分享。
public void GetEventDetail()
{
Delegate[] ds = UpdateWeather.GetInvocationList();
Console.WriteLine("注册客户名单:");
for (int i = 0; i < ds.Length;i++ )
{
Console.WriteLine("第"+i+"个客户:"+ds[i].Target.ToString());
Console.WriteLine(",调用方法" + ds[i].Method);
Console.WriteLine();
}
}
修改调用
感谢 右手交易 的支持和建议。
相关文章推荐
- CLR via C#(12)-委托Delegate
- CLR via C#(11)-无参属性、有参数属性(索引器)
- C#_C#中[],List,Array,ArrayList的区别及应用
- CLR via C#(10)-参数
- CLR via C#(09)-扩展方法
- CLR via C#(08)-操作符
- CLR via C#(07)-静态类,分部类
- C#学习笔记
- CLR via C#(06)- 构造器
- 如何创建C#版浮动工具栏?
- C# 扩展方法
- c#判断空字符串
- C# winform vs2013settings读写方法
- CLR via C#(05)- 访问限定、数据成员
- CLR via C#(04)- 本是同根生
- CLR via C#(03)- 对象创建和类型转换
- CLR via C#(02)-基元类型、引用类型、值类型
- CLR via C#(01)-.NET平台下代码是怎么跑起来的
- [C#]List的Sort()、Find()、FindAll()、Exist()的使用方法举例
- CLR via C#学习笔记----知识总概括