码农深耕 - 说说IDisposable
概要
C#提供了方便的垃圾回收机制,使我们几乎不再需要为资源管理费心。可事实上,能被垃圾回收释放掉的只是托管资源,非托管资源还是需要我们手动释放。而为了实现这一目的,C#提供了 IDisposable 接口,这篇文章就谈一谈 IDisposable 接口在使用中需要注意的地方。
实现
首先,IDisposable 接口非常简单,只包含一个方法 Dispose。在 IDisposable 接口的定义中可以看到明确的描述,它是用于释放非托管资源的 [1]。但是,想写出一个健壮的 IDisposable 实现却不是那么容易,好在微软为我们提供了一份详细的指南 [2][3],参照这份指南中的示例代码,我们就可以轻而易举的写出一份优秀的 IDisposable 接口实现代码了,这里不再进行详细说明。
那么那些资源是常见的非托管资源呢?根据我的经验,列举如下:
- 文件流
- 窗体句柄
- 图片
- 网络连接
- 数据库连接
在使用到上述资源时,不要忘记务必在使用之后调用它们的 Dispose 方法。为了保证资源释放,一般我们会利用 try / finally 块,在 finally 块中调用 Dispose 方法。针对这种需求,C# 为我们提供了 using 语法糖 [4],对于实现了 IDisposable 接口的对象,利用 using 语句,可以简单的完成资源释放。
需要注意的细节
注意事件退订
当我们调用了一个对象的 Dispose 方法之后,它的非托管资源就被释放掉了,但是这个对象仍然可以被访问。因此,如果在这个对象内订阅了其他对象的事件,务必在 Dispose 方法中将事件退订 [5]。否则,事件发布者再次触发事件时,这个已经释放掉资源的对象还是会响应该事件,如果在事件响应方法中尝试访问已经释放的资源,则会发生意料外的错误。
WinForm 控件
从父容器中移除控件
当我们从一个容器中将某个控件 Remove 掉,这个控件的句柄并不会被释放,如果我们忘记显示地调用该控件的 Dispose 方法,又频繁地创建、移除控件,很快就会因为句柄过多而发生异常,面对这种情况,往往一头雾水,很难找到发生异常的根本原因。在以往的工作中,我一般会选择将一个控件从容器中 Remove 之后,再调用该控件的 Dispose 方法。后来无意间发现直接调用控件的 Dispose 方法,它会自动将自己从父容器中移除,通过阅读源码 [6] 证实了这个特性,真的挺方便。
移除自己的子控件
上面提到调用一个控件的 Dispose 方法,会自动将自己从父容器中移除。那么 Dispose 方法会对自己的子控件产生什么影响呢?是否需要在调用 Dispose 之前,先遍历并释放所有子控件呢?答案是不用,控件会自动调用所有子控件的 Dispose 方法,通过源码 [7] 可以证实这一点。可见,控件的 Dispose 方法是没有副作用的,一旦调用,就可以带着自己的资源,消失在我们的系统中,这种实现的思路,值得我们借鉴学习。
结语
IDisposable 为我们提供了便利,弥补了自动垃圾回收的不足,掌握好这个接口,不仅可以使我们的开发水平更进一步,也可以让我们的产品稳定性更上层楼。
参考文献:
[1] IDisposable 接口 (https://docs.microsoft.com/en-us/dotnet/api/system.idisposable?view=netframework-4.7.2#definition)
[2] 清理非托管资源 (https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/unmanaged?view=netframework-4.7.2)
[3] Dispose 模式 (https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/dispose-pattern)
[4] using 语法糖 (https://docs.microsoft.com/en-us/dotnet/api/system.idisposable?view=netframework-4.7.2#the-c-and-visual-basic-using-statement)
[5] 取消订阅 (https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/events/how-to-subscribe-to-and-unsubscribe-from-events#unsubscribing)
[6] 从父容器中移除 (https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Control.cs,6013)
[7] 自动释放子控件的资源 (https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Control.cs,6017)
码农深耕 - 说说IDisposable的更多相关文章
- 【整理】待毕业.Net码农就业求职储备
声明:本文题目来源于互联网,仅供即将从学校毕业的.Net码农(当然,我本人也是菜逼一个)学习之用.当然,学习了这些题目不一定会拿到offer,但是针对就业求职做些针对性的准备也是不错的.此外,除了技术 ...
- <开心一笑> 码农 黑客和2B程序员之间的区别
笔记本电脑 码农: 黑客: 2B程序员: 求2的32次方: 码农: System.out.println(Math.pow(2, 32)); 黑客: System.out.println(1L< ...
- 经典算法C++版(参考一线码农博文)
鉴于一线码农的算法博文基本通过C#完成,此处用C++再实现一遍,具体解法可参考其博文. 地址:http://www.cnblogs.com/huangxincheng/category/401959. ...
- [2013 eoe移动开发者大会]靳岩:从码农到极客的升级之路
(国内知名Android开发论坛 eoe开发者社区推荐:http://www.eoeandroid.com/) 前天,2013 eoe 移动开发者大会在国家会议中心召开,eoe 开发者社区创始人靳岩在 ...
- 专门为码农定制的14款创意的T裇(T-Shirt)设计
T裇衫是人们在各种场合都可穿着的服装,如在T裇衫上作适当的装饰,即可增添无穷的韵味.通过图案直接反映人类的精神风貌,你可以把日常生活中的兴趣.习惯.喜怒哀乐.嗜好等展露无疑,张扬个性.秀出自我.对于码 ...
- 老码农教你在 StackOverflow 上谈笑风生
作为一个高大上的码农,你肯定用到过 StackOverflow,必须的.会有人否定这个断言么?那他恐怕不是真正的码农,或者说还没入门.StackOverflow 对于码农的重要性,基本就和诸葛亮对刘备 ...
- 上不了Google是码农的悲哀
http://refyt.com/?r=34d1edb7dba42e8d 上不了Google是码农的悲哀.1. 资料大部分都在国外的网站,差不多倍感伤心.2. Google Play没有办法访问了.3 ...
- .net 码农转战 iOS - 初探
好久没写博客了,之前还打算把毕业设计中涉及到的两个算法拿出来说说(脸型分析 + 声音分析),博文都写了一半了,后来实在太忙了,那篇随笔也就沉在草稿列表中没动过. 我原先是专职 .net 开发的,在公司 ...
- IT码农哥放弃50万年薪:辞职卖咖喱凉皮(背后深藏功与名)_互联网的一些事
IT码农哥放弃50万年薪:辞职卖咖喱凉皮(背后深藏功与名)_互联网的一些事 IT码农哥放弃50万年薪:辞职卖咖喱凉皮(背后深藏功与名)
随机推荐
- js表单验证控制代码大全
http://www.cnblogs.com/SAL2928/archive/2008/10/24/1319020.html目录: 1:js 字符串长度限制.判断字符长度.js限制输入.限制不能输入. ...
- List、Set、Map常见集合遍历总结
Java中的集合有三大类,List.Set.Map,都处于java.util包中,List.Set和Map都是接口,不能被实例化,它们的各自的实现类可以被实例化.List的实现类主要有ArrayLis ...
- EMQ学习 ---集群
emqttd集群设置管理 一.先来看EMQ的文档定义:http://emqtt.com/docs/v1/cluster.html emqttd集群设置管理 假设部署两台服务器s1.emqtt.io, ...
- 第23章、OnFocuChangeListener焦点事件(从零开始学Android)
在Android App应用中,OnFocuChangeListener焦点事件是必不可少的,我们在上一章的基础上来学习一下如何实现. 基本知识点:OnFocuChangeListener事件 一 ...
- HDU 4946 Area of Mushroom 共线凸包
题意是在二维平面上 给定n个人 每一个人的坐标和移动速度v 若对于某个点,仅仅有 x 能最先到达(即没有人能比x先到这个点或者同一时候到这个点) 则这个点称作被x占有 若有人能占有无穷大的面积 则输出 ...
- js 温故而知新 用typeof 来判断一个未定义的变量
一直以为,如果你使用一个未定义的变量,肯定会报错.甚至根本不可能有这种场景. 但仔细想想还是有的,譬如你要判断全局是否存在$变量.或者要为全局暴漏一个全局变量之前,先判断是否有这个变量. typeof ...
- Android 线性布局(LinearLayout)相关官方文档 - 布局參数部分
Android 线性布局(LinearLayout)相关官方文档 - 布局參数部分 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商 ...
- Python3中使用HTMLTestRunner报No module named 'StringIO'解决方法
今天在学习使用HTMLTestRunner生成测试报告时遇到一个报错,如图所示: 网上搜索了下“No module named 'StringIO'”解决方法,原来我用的是Python 3.X版本,而 ...
- android studio 使用问题记录
android studio 使用问题记录 下载地址:FQ或园子内好心人提供的国内地址: http://www.cnblogs.com/bjzhanghao/archive/2012/11/14/an ...
- 判断是否是IE浏览器和是否是IE11
判断是否是IE浏览器用下面这个函数, function isIE() { //ie? 是ie返回true,否则返回false if (!!window.ActiveXObject || "A ...