safehandle 和析构函数
safehandle 是一种析构机制,她和析构函数有什么分别。
首先要理解析构函数。析构函数在.net中是没有顺序的,因此你不能假定另一个对象的析构函数在你之后运行,哪怕它是你的成员!如果你的成员也有析构函数,那么你能做什么,什么不应该做?
第一,在析构函数运行时,你不应该假设它没清理资源,而去试图清理它。合理的做法是它应该自己实现dispose模式,你在dispose(true)段落可以调用它的dispose()函数.因为dispose是可多次重入的,因此不会有问题。如果它没有,那就别去理他,因为它的析构函数会释放它的非托管资源。这样的好处是,我可以分别控制每一个实现dispose模式的对象成员的控制时机,而dispose(false)也就是析构函数,能够作为防御性代码,帮你把忘记的“非托管”资源清理掉。
第二,一个实现了dispose的.net对象,外部应该怎样看它?不应该把它所控制的资源看作非托管资源,既然他实现了dispose,也就是“有自行管理”的,因此只需要在dispose(true)段落调用它的dispose函数,让其在显式清理实际时产生效果便可。这是我对dispose模式的理解。dispose模式分两类资源,一类是托管,一类是非托管。托管和非托管并不是纯粹站在.net角度出发,而是应该理解为“自己管理”和“其他对象管理”的差别。你的对象自己打开文件,就自己负责关闭,而其他对象,包括成员对象,他们控制的资源就由他们控制,在当前立场上看,都是“受托管的”。
第三,你的对象的 dispose 应该被显式调用(也就是最外层对象)!这个是dispose模式的关键,因为析构函数只是负责自身非托管资源的释放,它没有参与整套资源管理流程。如果你不显式调用(或者另外编写代码),清理流程是不可能正确执行的。
第四。为何析构函数不负责dispose的所有内容,首先是析构顺序的不确定性,而资源管控流程需要顺序;其次,析构函数没有明确的调用时机,而dispose可以在任意时刻调用。
然后是safehandle,safehandle据说有经过优化,但是它也不会抢先在析构函数阶段运行,在我测试中是这种情况。因此,我不知道优化在那里了。只是添加了一种模式,比析构函数更舵控制,毕竟是外部独立的类,而且系统已经针对多种资源提供了恰当的子类,可惜没有针对com对象资源。
总的来说,最佳实践是:
1.如果safehandle子类有的系统资源,如句柄,非托管内存等等,用safehandle 模式。
2.如果子成员正确实现了dispose,把它视为托管资源,在dispose(true)中调用。
3.如果子成员没有实现dispose,但是控制了相关资源,也就是你要负责子对象相关资源的显式控制,千万别用析构函数清理,因为析构函数阶段,子成员可能已经把它关联的资源给释放掉了(未必以正确的方式,只是对资源失去控制力),你无法再清理。因为GC对任意对象的析构函数调用顺序是不确定的。(这一状况只能要求你在编程阶段正确调用dispose,而绝不能遗忘调用,否则就有资源泄漏。com for .net就是如此设计的)
4.一般情况,dispose(true)负责对象链的清理流程,dispose(false)即析构函数,负责自身非托管资源。如果没有这部分可以不写析构函数。
5.dispose的实现方式要规范。最终dispose要显式调用!
规范的dispose该注意哪些,这里补充一下:
private bool disposedValue = false; // 要检测冗余调用
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// TODO: 释放托管状态(托管对象)。
//这里应该包含成员对象的dispose
//大部分被包装的资源的处理过程都写在这里,比如退出过程:先保存,然后关闭,等等
//safehandle.Dispose();
}
// TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
// TODO: 将大型字段设置为 null。
//这里是自身管理的一些资源的释放,比如通过c api调用的一些非托管资源
app = null;
disposedValue = true;
}
}
//TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
~Excel()
{
// 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
Dispose(false);
}
// 添加此代码以正确实现可处置模式。
void IDisposable.Dispose()
{
// 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
Dispose(true);
// TODO: 如果在以上内容中替代了终结器,则取消注释以下行。
//也就是有析构函数就有下面这行代码,表示显式运行dispose时,GC不需要再运行析构函数,提高性能
GC.SuppressFinalize(this);
}
safehandle 和析构函数的更多相关文章
- SafeHandle和Dispose z
SafeHandle最大的意义是封装一个托管资源且本身会执行.NET中的资源释放模式(所谓的Dispose Pattern),这样,开发者在使用非托管资源时,不可以不需要执行繁琐的资源释放模式,而直接 ...
- .NET 基础 一步步 一幕幕[面向对象之构造函数、析构函数]
构造函数.析构函数 构造函数: 语法: //无参的构造函数 [访问修饰符] 函数名() :函数名必须与类名相同. //有参的构造函数 [访问修饰符] 函数名(参数列表):函数名必须与类名相同. 作用: ...
- 【C#】析构函数
MSDN paper 析构函数 析构函数(destructor) 与构造函数相反,当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统自动执行析构函数. 析构函数往往用来做“清理善后” 的工作( ...
- c++虚析构函数
虚析构函数的作用主要是当通过基类指针删除派生类对象时,调用派生类的析构函数(如果没有将不会调用派生类析构函数) #include <iostream> using namespace st ...
- 转:Delphi2010新发现-类的构造和析构函数功能
Delphi2010发布了. 虽然凭着对Delphi的热爱第一时间就安装了,但是现在可能是年纪大了,对新事物缺乏兴趣了.一直都没有仔细研究. 今天有点时间试了一下新功能. 本来C#和Delphi.NE ...
- c++单例模式为什么不在析构函数中释放静态的单例对象(转)
需要清楚一下几点: 1.单例中的 new 的对象需要delete释放. 2.delete释放对象的时候才会调用对象的析构函数. 3.如果在析构函数里调用delete,那么程序结束时,根本进 ...
- C++构造函数/析构函数 设置成private的原因
C++构造函数/析构函数 设置成private的原因 标签(空格分隔): c/c++ 将构造函数,析构函数声明为私有和保护的,那么对象如何创建? 已经不能从外部调用构造函数了,但是对象必须被构造,应该 ...
- 关于GC和析构函数的一个趣题
这个有趣的问题感谢装配脑袋友情提供. 请看如下代码: public class Dummy { public static Dummy Instance; ; ~Dummy() { Instance ...
- C++构造函数和析构函数
构造函数简介 在上一个章节我们在创建好类的对象之后,首先对它的每一个成员属性赋值之后再对它们进行输出操作,如果不赋值就输出,这些值就会是垃圾值.而为了代码的简介,一次性为所有成员属性初始化,C++的类 ...
随机推荐
- 手机浏览器不支持 IDBObjectStore.getAll
最近在学习IndexDB,使用了IDBObjectStore.getAll,发现手机上不支持. 后面,查阅了mdn:  的确是不支持,且可以看到这个函数现在兼容性很差. 解决方法: 1.使用 IDB ...
- Web前端开发css基础样式总结
颜色和单位的使用 颜色 用颜色的名字表示颜色,比如:red 用16进制表示演示 比如:#FF0000 用rgb数值表示颜色,rgb(红,绿,蓝),每个值 ...
- 原生js使用forEach()与jquery使用each遍历数组,return false 的区别
原生js使用forEach()与jquery使用each()遍历数组,return false 的区别: 1.使用each()遍历数组a,如下: var a=[20,21,22,23,24]; $.e ...
- 源码安装ipython,并在ipython中整合spark
一.安装ipython 下载ipython, https://pypi.python.org/packages/source/i/ipython/ipython-2.2.0.tar.gz#md5=b9 ...
- 【原】设置iOS项目BuildVersion自动增加
一.概念阐述:Build与Version的区别 在iOS中有两种“版本号”,也就是所谓的version号与build号,如下图所示: 我们用最简洁的语言来区分这两个版本号的区别以及用途如下: Vers ...
- android四大组件之Broadcast
广播的概念 现实中:我们常常使用电台通过发送广播发布消息,买个收音机,就能收听 Android:系统在产生某个事件时发送广播,应用程序使用广播接收者接收这个广播,就知道系统产生了什么事件.Androi ...
- Play Framework 完整实现一个APP(七)
1.添加验证码 Application Controller添加captcha() public static void captcha() { Images.Captcha captcha = Im ...
- #研发解决方案介绍#基于StatsD+Graphite的智能监控解决方案
郑昀 基于李丹和刘奎的文档 创建于2014/12/5 关键词:监控.dashboard.PHP.graphite.statsd.whisper.carbon.grafana.influxdb.Pyth ...
- EntityFramework简介
EntityFramework是什么? 1.是对ADO.NET 更高封装的ORM (对象关系映射)框架,跟Nhibernate类似 2.用面向对象的方式来操作关系数据库 3.目标: 提高开发效率,减轻 ...
- JavaScript(js)的replace问题的解决
我是前端的门外汉,js我用得比较少.今天意外发现js自带的replace “居然”只替换1处,而其它的许多许多语言都是替换全部的. 你可能会说,切,我早就知道.高手请绕道. 你可能会说,用js的正则就 ...