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++的类 ...
随机推荐
- javascript中的一些核心知识点以及需要注意的地方
前言 近期杂事甚多,这些事情的积累对知识体系的提升有好处,但是却不能整理出来,也整理不出来 比如说我最近研究的Hybrid在线联调方案便过于依赖于业务,就算分享也不会有人读懂,若是抽一点来分享又意义不 ...
- 如何基于OM模型使用C#在程序中给SharePoint的BCS外部数据类型的字段赋值
概述: 外部内容类型和数据,SharePoint从2010这个版本开始就对BCS提供非常强大的支持,点点鼠标就可以取代以前直接编辑XML的方式来设置SharePoint到SQL数据库的连接.非常方便地 ...
- 你真的了解UITabBarController吗?
一:首先查看一下关于UITabBarController的定义 NS_CLASS_AVAILABLE_IOS(2_0) @interface UITabBarController : UIViewCo ...
- Java避免创建不必要的对象
小Alan最近看到了<Effective Java>这本书,这本书包含的内容非常丰富,这本书我就不多介绍了,只能默默的说一句,作为一名java开发错过了这本书难免会成为一个小遗憾,所以还是 ...
- Play Framework 完整实现一个APP(四)
上一篇最后出现的错误是因为断言 assertEquals(1, Post.count()); 出错,取到的Post的数量不是1,运行Test之前,表中有数据 可以添加以下方法,运行Test前清空数据 ...
- [LoadRunner]LR11安装或破解时报错的解决方法
背景:在性能测试项目上,需要安装到LR11进行性能测试,而在安装时会出现安装运行环境失败,安装文件缺失等问题.现总结了上述问题,并给出以下解决方法: 问题1:安装LoadRunner时出现“计算机缺少 ...
- SQL Server中的“最大并行度”的配置建议
SQL Server中的最大并行度(max degree of parallelism)如何设置呢? 设置max degree of parallelism有什么好的建议和指导方针呢?在微软官方文档R ...
- Win7 安装SQL SERVER 2012需要SP1补丁
在操作系统Win7上安装SQL Server 2012时,报如下错误: 也就是说SQL Server 2012如要要安装在Windows 7 上,则至少需要安装SP1补丁.否则就会弹出上面提示信息.关 ...
- Remote table-valued function calls are not allowed
在SQL Server中,在链接服务器中调用表值函数(table-valued function)时,会遇到下面错误: SELECT * FROM LNK_TEST.TEST.DBO.TEST(12) ...
- [AlwaysOn Availability Groups]SQL Server错误日志(AG)
SQL Server错误日志(AG) SQL Server错误日志会记录影响AG的时间,比如: 1.和Windows故障转移集群交互 2.可用副本的状态 3.可用数据的状态 4.AG endpoint ...