析构函数与IDisposable?

我已经阅读了在C#中处理对象/ IDisposable接口和析构函数,但对我来说,他们似乎做同样的事情?

两者有什么区别? 为什么我会用另一个呢? 事实上,在这个例子中(下面的链接),这段代码使用了IDisposable接口和一个析构函数:

http://msdn.microsoft.com/en-us/library/system.idisposable.aspx

评论说,析构函数是如果没有使用终结代码,但我该如何决定何时使用一个?

我写了一篇相当深入的文章,它应该有助于解释终结器,IDisposable,以及何时应该使用其中一个: http : //gregbee.ch/blog/implementing-and-using-the-idisposable-interface

可能最相关的部分是引用如下:

在使用非托pipe资源(如句柄和数据库连接)时,应使用延迟获取和早期发布的原则,确保它们保持最less的时间。 在C ++中,释放资源通常在析构函数中完成,析构函数在删除对象的位置确定运行。 但是,.NET运行时使用垃圾回收器(GC)清理和回收不再可访问的对象所使用的内存; 因为它定期运行,这意味着你的对象被清理的地方是不确定的。 这样做的结果是,pipe理对象不存在析构函数,因为没有确定的位置来运行它们。

除了析构函数之外,C#还有终结器,这些终结器是通过重写在基类Object类上定义的Finalize方法来实现的(尽pipeC#在某种程度上使用了C ++析构函数语法〜Object)。 如果一个对象覆盖了Finalize方法,而不是在GC超出范围时被GC收集,GC将它放在一个终结器队列中。 在下一个GC循环中,队列上的所有终结器都将运行(在当前实现中的单个线程上),并且回收最终对象中的内存。 这很明显,为什么你不想在终结器中进行清理:需要两个GC周期来收集对象,而不是一个,并且有一个单线程,所有终结器都运行,而其他每个线程都被挂起。这将会损害业绩。

所以如果你没有析构函数,并且你不想把清理工作留给终结器,那么唯一的select就是手动确定地清理对象。 inputIDisposable接口,该接口提供了支持该function的标准,并定义了一个方法Dispose,放置对象的清理逻辑。 当在finally块中使用时,此接口为析构函数提供等效的function。 代码中最后阻塞的原因主​​要是支持IDisposable接口; 这就是为什么C ++使用简单的尝试/除了因为不需要使用析构函数的finally块。

简洁版本

终结者给你一个机会来处置非托pipe资源,以防对象的用户忘记调用IDisposable.Dispose

如果您的对象实现了IDisposable ,那么您的对象的用户必须调用.Dispose 。 你不必清理用户的混乱; 但这是一件很好的事情。


我在Stackoverflow上最stream行的答案是从一开始就让你知道为什么你有IDisposable,它应该做什么,你的终结器可以做什么,它不应该做什么。

这个答案融化了面孔

已被用来形容它:P

在托pipe的编程语言中使用析构函数(〜Object())是最为愚蠢的想法。 像C,C ++这样的非托pipe语言在使用RAII语言的时候会有析构函数,但是像Java,C#这样的pipe理就是如此荒谬。

Java Collection Framework的前任项目负责人Joshua Bloch指出,Java中的finalize()方法(相当于C#的C ++类似析构函数)的想法是有史以来最大的错误。 与C#相同,Java中的finallize()会给“new”带来开销,因为它必须在分配期间添加到finallizer队列中。 更重要的是,垃圾收集器必须在队列中popup并运行finallize(),所以gc期间的开销是两倍。

C#有许多增强function,例如“using(IDisposable){}”,它不仅允许将IDisposablevariables限制在“using”块的范围内,而且还保证清理。 我的问题是,为什么C#遵循Java的相同path导致了很大的错误。 也许是在2003年〜2005年左右开始dotnet的开发,很多Java架构师发现finallize()的谬误,那么这个错误就会被阻止。

一种语言的许多好主意经常被转移到其他语言,如C#中的“IDisposable / using combo”,在其“try(object-to-dispose){}”语句中转移到Java 1.7。 但是,语言build筑师在从一个人转移到另一个人的过程中,并没有发现这个坏主意被伪装成好主意。

我build议不要使用〜Destructor(),并坚持IDisposable /使用组合,如果你需要手动清理像数据库连接的非托pipe资源。