.Net开发笔记(六)关于事件(续)

简介:

上一篇最后提到了怎么解决由“事件编程”引起的内存泄露问题,最后几句说到了由“弱引用”的概念引申出来“弱委托”。具体没说怎么去实现,这篇文章介绍一下具体实现过程。(请先看前一篇文章)

先来看一下MSDN上对Delegate(委托)的解释:

表示委托,委托是一种数据结构,它引用静态方法或引用类实例及该类的实例方法。

我们先不去管网上对“委托”的其他形象比如,比如“类似函数指针”、“对同一类方法的签名”等等。先来看看MSDN上的解释是个什么意思。首先它是一种数据结构,基本可以看做包含两个东西,一个是方法,一个是方法的所有者,即对象(静态方法的所有者为类)。那么我们可以简单的用图来画一下:

图1

如果对委托比较熟悉的人可能已经知道,所有我们定义的委托变量,都有两个属性Target和Method,这也正验证了上图的正确性。

那么Event(事件)是个什么东西?看一下MSDN对“事件”的一段解释:

在发生其他类或对象关注的事情时,类或对象可通过事件通知它们。发送(或引发)事件的类称为“发行者”,接收(或处理)事件的类称为“订户”。

这个解释基本上没什么用,因为它跟之前谈到的“委托”没任何联系,那我们再回忆一下我们之前在代码中是怎么去定义一个事件的?书上说网上也说,定义一个委托变量,在声明前面加一个event关键字,event关键字小写,那么这个委托变量就可以叫事件,编写代码时,VS IDE智能提示会在事件前面有一个“闪电”的图标。那么,根据这个描述,事件明显就是一种特殊的委托实例,没错,事件就是一种特殊的委托实例,它具备所有委托所具备的特点(有一些限制,跟主题没关系,略过)。

当事件的观察者(Observer)向事件的发布者(Subject)注册一个事件时,事件发布者就会产生一个对事件观察者的强引用(strong reference)(不然,当事件发生时,怎么才能通知观察者),也就是说,“注册事件”这个动作将事件的发布者和事件的观察者绑定到了一起,具体体现在:发布者包含了一个对观察者的强引用。

结合上一篇文章中的“图2”,我们可以看出,一个事件对应一个委托链,激发事件的过程可以看做:遍历这个委托链,在每一个节点中的Target上调用Method。这就完成了“事件发布者->激发事件->通知观察者->观察者响应事件->调用事件处理程序”这一过程。那么,对于一个事件,每被注册一次,它对应的委托链上就应该增加一个节点,该节点中存储着观察者的信息,由于同一个事件,同一个对象可能注册好几次,因此某一事件对应委托链中的节点的个数并不等于该事件的观察者数目,一般前者大于后者。再来看一张图:

图2

由此看出,委托链维持着事件发布者与事件观察者之间的联系,在某些情况下,当我们认为我们程序中的观察者已死(代码中再没有对观察者的引用),GC会回收观察者的内存时,实际情况往往不是我们认为的这样,由于委托链中仍然有对观察者的强引用,GC是不会对它进行内存回收的,这样一来,如果观察者数目大,观察者属于大对象,系统运行时间过长,就会导致内存不足。

注:GC回收对象内存的前提是程序中不再有该对象的强引用(strong reference)。

解决以上问题关键在于,怎么在观察者即将死亡的时候通知发布者将自己的引用删除,但是这个几乎做不到,因为你根本不知道观察者什么时候死亡,再者,当系统复杂庞大之后,你根本不知道谁是谁的观察者,谁又暗自拥有谁的强引用。所以,最好的情况是,观察者在必要的时候,能够正常的被GC回收内存,对于事件发布者来说,观察者的存在与否没有多大关系,如果观察者还存在,那么当事件发生时就通知观察者,如果观察者不存在了,那么当事件发生时就不通知观察者。这就要求事件发布者对于观察者之间的关联不能像之前那种“强引用”的关系,而应该是“弱引用”的关系。

因此,我们可以仿照原有的Delegate数据结构,模拟一种新的数据结构,将原来Target这个“强引用”变为“弱引用”,我们取名叫做“弱委托”(WeakDelegate),代码类似如下:

View Code

包含两个属性WeakTarget和Method,分别对应原来委托的Target和Method属性,一个Invoke公共方法,对应原来委托的Invoke方法,用于执行委托。

由此一来,图2中委托链中的各个节点就可以由原来的Delegate(其派生类,我们自己定义的委托)变为我们现在的WeakDelegate,那么在写事件发布者类(Subject)的代码时,我们需要自己来维持这些委托链了,如下:

View Code

在事件发布者中,我定义了三个使用我们自己WeakDelegate的事件,由_delegateList管理,分别是XX1、XX2、XXn事件,他们对应的委托链中的每一个节点属于WeakDelegate类型,不会保存观察者的强引用。另外为了对比,我定义了一个传统的使用Delegate的事件CommonEvent,它对应的委托链中的每一个节点属于Delegate(派生类)类型,保存观察者的强引用。

定义了一个观察者(Observer)类,代码为:

View Code

该类除了注册Subject类的事件外,没有其他内容,当事件发生后,输出与该事件相关的信息。

测试代码如下:

View Code

被注释部分事件发布者与观察者之间属于弱关联,观察者能够正常死亡;未被注释部分事件发布者与观察者属于强关联,观察者不能正常死亡。

运行结果如下:

图3

图4

本文代码均已调试通过,环境(XP+.net 3.5)。

本文所有事件,均没有考虑“多线程”情况。

希望有帮助,O(∩_∩)O~

 

 

作者:周见智 
出处:http://www.cnblogs.com/xiaozhi_5638/ 
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

分类:  .NET Framework
标签:  c#委托

本文转自周见智博客博客园博客,原文链接:http://www.cnblogs.com/xiaozhi_5638/archive/2013/01/17/2864983.html,如需转载请自行联系原作者
目录
相关文章
|
13天前
|
人工智能 量子技术 C#
【专栏】.NET 开发:开启数字化新时代
【4月更文挑战第29天】.NET开发在数字化新时代中发挥关键作用,借助跨平台能力、高性能和现代编程语言支持,如C#,助力企业实现数字化转型。通过企业级应用开发、移动应用和云计算集成,.NET加速业务流程和提升用户体验。未来,.NET将涉足AI、ML、MR/AR及量子计算,持续推动技术创新和数字化转型。开发者应提升技能,适应高性能需求,把握发展机遇。
|
13天前
|
缓存 监控 算法
【专栏】.NET 开发:实现卓越性能的途径
【4月更文挑战第29天】本文探讨了.NET开发中的性能优化,强调了理解性能问题根源和使用分析工具的重要性。基础优化包括代码优化(如减少计算、避免内存泄漏)、资源管理及选择合适算法。高级策略涉及并行编程、缓存策略、预编译(AOT)和微服务架构。持续性能测试与监控是关键,包括性能测试、监控分析和建立优化反馈循环。开发者应持续学习和实践性能优化,以构建高性能应用。
|
13天前
|
开发框架 .NET C#
【专栏】理解.NET 技术,提升开发水平
【4月更文挑战第29天】本文介绍了.NET技术的核心概念和应用,包括其跨平台能力、性能优化、现代编程语言支持及Web开发等特性。文章强调了深入学习.NET技术、关注社区动态、实践经验及学习现代编程理念对提升开发水平的重要性。通过这些,开发者能更好地利用.NET构建高效、可维护的多平台应用。
|
13天前
|
机器学习/深度学习 vr&ar 开发者
【专栏】.NET 技术:引领开发新方向
【4月更文挑战第29天】本文探讨了.NET技术如何引领软件开发新方向,主要体现在三方面:1) 作为跨平台开发的先锋,.NET Core支持多操作系统和移动设备,借助.NET MAUI创建统一UI,适应物联网需求;2) 提升性能和开发者生产力,采用先进技术和优化策略,同时更新C#语言特性,提高代码效率和可维护性;3) 支持现代化应用架构,包括微服务、容器化,集成Kubernetes和ASP.NET Core,保障安全性。此外,.NET还不断探索AI、ML和AR/VR技术,为软件开发带来更多创新可能。
|
13天前
|
物联网 vr&ar 开发者
【专栏】.NET 技术:为开发注入活力
【4月更文挑战第29天】本文探讨了.NET技术的创新,主要体现在三个方面:1) .NET Core实现跨平台开发革命,支持多种操作系统和硬件,如.NET MAUI用于多平台UI;2) 性能提升与生产力飞跃,C#新特性简化编程,JIT和AOT优化提升性能,Roslyn提供代码分析工具;3) 引领现代化应用架构,支持微服务、容器化,内置安全机制。未来,.NET 7将带来更多新特性和前沿技术整合,如量子计算、AI,持续推动软件开发创新。开发者掌握.NET技术将赢得竞争优势。
|
Android开发
.Net 转战 Android 4.4 日常笔记(8)--常见事件响应及实现方式
原文:.Net 转战 Android 4.4 日常笔记(8)--常见事件响应及实现方式 在Andrioid开发中,常见的事件如下 单击事件 OnClickListener 长按事件 OnLongClickListener 滑动事件 OnTouchListenner 键盘事件 OnKeyListenner 焦点事件 setOnFoucsChangeListener 设置方式 1.
1221 0
|
4月前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
46 0
|
17天前
|
开发框架 前端开发 JavaScript
JavaScript云LIS系统源码ASP.NET CORE 3.1 MVC + SQLserver + Redis医院实验室信息系统源码 医院云LIS系统源码
实验室信息系统(Laboratory Information System,缩写LIS)是一类用来处理实验室过程信息的软件,云LIS系统围绕临床,云LIS系统将与云HIS系统建立起高度的业务整合,以体现“以病人为中心”的设计理念,优化就诊流程,方便患者就医。
22 0
|
2月前
|
开发框架 前端开发 .NET
进入ASP .net mvc的世界
进入ASP .net mvc的世界
32 0