跟小静读CLR via C#(13)-浅谈事件

简介:

提起事件,我们都不陌生,事件使类之间有了交互的能力。它是建立在委托基础上的。有了前面对委托的了解,相信读起事件来也不会太难了。关于事件,现成的好文章数不胜数,本不打算写了。不过问道有先后,各抒己见,也不为过。想了想,还是不偷懒了,最起码能逼自己动动手,多理解几分。


一、 事件能干什么?

类通过维护一个已登记事件列表,当事件发生的时候可以通知已登记的方法。主要功能:

  • 方法登记对该事件的关注;
  • 方法注销对该事件的关注;
  • 事件发生时,登记了的方法会收到通知,作出相应的反应。

      Ps:看到这几点的时候,总会不自觉地想起观察者模式。

二、 怎样定义事件?

举个简单的例子:现在有一个天气预报信息发布中心,并且有短信天气预报和电视台天气预报两个客户订阅了天气信息。当新的天气数据到达后,信息发布中心会发送通知,此时短信和电视台天气预报均可以做出相应的发布。

clip_image001

实现过程:

1. 定义类来包含要传递的通知内容——天气预报信息

clip_image003

按照约定,该类应该继承自EventArgs类,并且类名形如***EventArgs。通常该类需要定义私有字段及相应的只读公共属性。

2. 定义事件管理类——信息发布中心

        clip_image005

  • 首先定义事件:   要求public标识符; event关键字; 委托类型; 事件名称。

clip_image007

         本例中委托类型为EventHandler<WeatherEventArgs>,泛型System.EventHandler的定义为:

clip_image009

         因此,要求登记该事件的方法的形式为:

          void MethodName(object sender,WeatherEventArgs e);

  • 然后定义一个受保护的虚方法,包含一个WeatherEventArgs参数。它检查一下登记列表是否为空,如果不为空则引发委托。
  • 最后定义一个方法,接收输入信息,并且调用上面定义的虚方法。这是向外部公开的触发事件的方法,来通知所有的已登记方法。
ILDasm.exe查看一下WeatherManager类?

clip_image013

  • 虽然事件定义为Public,但是产生的相应的委托字段为private。
  • 生成了以add_和remove_开头的事件,这两个事件分别对应System.Delegate的静态方法Combine()和Remove。这些在 委托 那一节已经提到过了。
  • 事件定义记录项,主要包括一些标记和add,remove访问器方法,建立事件与访问器的关系。它的IL部分代码如下:

          clip_image015

3. 定义事件接收类——短信中心、电视台天气预报

首先以电视台播报类为例:

image

  • 在构造器中传入WeatherManager实例参数。其中的+=操作部分实际上是add_**方法,将委托添加到事件的列表中,完成委托的登记。

clip_image019

  • 类似的定义了UnRegWeather方法来注销委托。
  • 上面已经提到过,由于上面声明事件时委托类型为EventHandler<WeatherEventArgs>,因此登记事件的方法参数形式是固定的。也就是                                 void WeatherForcast(object sender,WeatherEventArgs e)。
  • 短信中心的实现十分类似,不再赘述了,代码如下。

clip_image020

4. 实际调用,触发事件

clip_image021

image

 

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();
            }
        }

 

修改调用

image

image

感谢 右手交易 的支持和建议。


关于事件就和大家分享这么多了,又是一个Happy Ending。

 




    本文转自 陈敬(Cathy) 博客园博客,原文链接:http://www.cnblogs.com/janes/archive/2011/09/08/2170968.html,如需转载请自行联系原作者


相关文章
c# Gridview 点击checkbox 触发的事件
c# Gridview 点击checkbox 触发的事件
由浅入深理解C#中的事件
由浅入深理解C#中的事件
380 19
|
C#
C#一分钟浅谈:委托与事件的实现方式
本文详细介绍了C#编程中委托与事件的基础知识及应用场景。首先解释了委托的概念,包括定义与使用方法;接着介绍了事件这一基于委托的特殊类型,展示了如何在类中定义事件及跨类订阅与处理事件;最后讨论了常见问题如事件未处理异常、重复订阅及内存泄漏等,并提出了相应的解决方案。通过本文,读者将全面掌握委托与事件的使用技巧,提升应用程序的设计与开发水平。
531 7
|
C++ 安全 存储
C++智能指针解析
C++智能指针解析
384 0
C++智能指针解析
|
存储 算法 C++
Hash与布隆过滤器
Hash与布隆过滤器
246 0
Hash与布隆过滤器
|
图形学 C# 开发者
全面掌握Unity游戏开发核心技术:C#脚本编程从入门到精通——详解生命周期方法、事件处理与面向对象设计,助你打造高效稳定的互动娱乐体验
【8月更文挑战第31天】Unity 是一款强大的游戏开发平台,支持多种编程语言,其中 C# 最为常用。本文介绍 C# 在 Unity 中的应用,涵盖脚本生命周期、常用函数、事件处理及面向对象编程等核心概念。通过具体示例,展示如何编写有效的 C# 脚本,包括 Start、Update 和 LateUpdate 等生命周期方法,以及碰撞检测和类继承等高级技巧,帮助开发者掌握 Unity 脚本编程基础,提升游戏开发效率。
955 0
|
存储 安全 C#
C# - 委托与事件
这篇文档介绍了C#中的委托和事件。委托是存储方法引用的类型,支持回调、事件处理,具有引用方法、类型安全、多播性等特性,并在异步编程中发挥作用。事件是委托的封装,提供保护和订阅机制,防止外部直接访问。当需要在类内部控制方法调用,防止外部误触发时,可使用事件。
409 2
C# Dev解决gridview1_SelectionChanged和gridview1_RowCellClick事件触发两次等问题
C# Dev解决gridview1_SelectionChanged和gridview1_RowCellClick事件触发两次等问题
C# Dev解决gridview1_SelectionChanged和gridview1_RowCellClick事件触发两次等问题
C#||委托和事件的实例
C#||委托和事件的实例
220 0