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++的类 ...
随机推荐
- 基本排序算法——基数排序java实现
基数排序 package basic.sort; import java.util.Arrays; import java.util.Random; public class RadixSort { ...
- 基本排序算法——选择排序java实现
选择排序与冒泡排序有很大的相同点,都是一次遍历结束后能确定一个元素的最终位置,其主要思路是,一次遍历选取最小的元素与第一个元素交换,从而使得一个个元素有序,而后选择第二小的元素与第二个元素交换,知道, ...
- 【百度文库课程】Java语言基础与OOP入门学习笔记一
一. Java的历史与由来 原名Oak,针对嵌入式系统开发设计,语法与C/C++基本一致 二. Java语言特点 Java由四方面组成:Java编程语言.Java类文件格式.Java虚拟机和Java应 ...
- python之socket-ssh实例
本文转载自大王http://www.cnblogs.com/alex3714/articles/5830365.html 加有自己的注释,应该会比原文更突出重点些 一. 基本Socket实例 前面讲了 ...
- ORA-01078: failure in processing system parameters & LRM-00109: could not open parameter file
安装了Oracle 12C后,启动数据库的过程中出现如下错误 SQL> startup ORA-01078: failure in processing system parameters LR ...
- Ignite用户配置管理介绍
Ignite8这款数据库性能监控.性能分析软件,不光是DBA监控.管理数据库的利器之一,开发人员也可以查看系统性能数据,下面介绍一下如何在Ignite里面配置用户权限,本文纯水文一篇,介绍简单基本的配 ...
- [MySQL] Buffer Pool Adaptive Flush
Buffer Pool Adaptive Flush 在MySQL的帮助文档中Tuning InnoDB Buffer Pool Flushing提到, innodb_adaptive_flushin ...
- JavaSe:Cookie 管理的API介绍
CookieManager 在使用HttpURLConnection中,并没有关于Cookie的管理.如果使用Java程序时,怎么管理cookie呢? Cookie案例 1. User Agent - ...
- SQL Server 2008 R2——统计各部门某年入职人数
=================================版权声明================================= 版权声明:原创文章 谢绝转载 请通过右侧公告中的“联系邮 ...
- mybatis 动态sql表达式相关应用
一.mybatis 表达式简介 对于mybatis3 ,提供了一种动态sql的方式.通过动态sql我们可以直接在mybatis 的xm映射文件中直接通过条件判断的方式进行查询添加的拼接.mybatis ...