什么时候在类而不是析构函数上实现IDispose?我读了这篇文章,但是我仍然没有抓住重点。
我的假设是,如果我在对象上实现IDispose,则可以显式地“销毁”该对象,而不是等待垃圾回收器执行此操作。这样对吗?
这是否意味着我应该始终在对象上显式调用Dispose?常见的例子有哪些?
什么时候在类而不是析构函数上实现IDispose?我读了这篇文章,但是我仍然没有抓住重点。
我的假设是,如果我在对象上实现IDispose,则可以显式地“销毁”该对象,而不是等待垃圾回收器执行此操作。这样对吗?
这是否意味着我应该始终在对象上显式调用Dispose?常见的例子有哪些?
Answers:
终结器(也称为析构函数)是垃圾回收(GC)的一部分-它不确定何时(或什至)发生,因为GC主要是由于内存压力(即需要更多空间)而发生的。终结器通常仅用于清理非托管资源,因为托管资源将具有自己的收集/处置。
因此IDisposable
用于确定性地清理对象,即现在。它不收集对象的内存(仍然属于GC),但是用于关闭文件,数据库连接等。
之前有很多主题:
最后,请注意,IDisposable
对象也具有终结器并不罕见。在这种情况下,Dispose()
通常调用GC.SuppressFinalize(this)
,这意味着GC不会运行终结器-它只会丢弃内存(便宜得多)。如果您忘记了Dispose()
该对象,则终结器仍将运行。
该Finalize()
方法的作用是确保垃圾回收时 .NET对象可以清除不受管的资源。但是,应尽快释放诸如数据库连接或文件处理程序之类的对象,而不要依赖于垃圾回收。为此,您应该实现IDisposable
接口,并释放Dispose()
方法中的资源。
在MSDN上有一个很好的描述:
此接口的主要用途是释放非托管资源。当不再使用托管对象时,垃圾收集器会自动释放分配给该对象的内存。但是,无法预测何时会发生垃圾回收。此外,垃圾收集器不了解 诸如窗口句柄或打开的文件和流之类的非托管资源。
使用此接口的Dispose方法 与垃圾回收器一起显式释放非托管资源。当不再需要该对象时,该对象的 使用者可以调用此方法。
C#析构函数中唯一应有的内容是此行:
Dispose(False);
而已。该方法别无其他。
关于是否应始终致电Dispose
的问题通常是激烈的辩论。请参见本博客为从.NET社区尊重个人一个有趣的视角。
就我个人而言,我认为杰弗里·里希特(Jeffrey Richter)的观点Dispose
是非强制性的,这一点极其薄弱。他举两个例子来证明自己的观点。
在第一个示例中,他说Dispose
在主流情况下调用Windows Forms控件是乏味且不必要的。但是,他没有提到Dispose
在那些主流场景中,控制容器实际上会自动调用它。
在第二个示例中,他指出,开发人员可能错误地假定IAsyncResult.WaitHandle
应该主动处置该实例,而没有意识到该属性懒惰地初始化了等待句柄,从而导致不必要的性能损失。但是,此示例的问题在于,它IAsyncResult
本身不遵守Microsoft自己发布的有关处理IDisposable
对象的准则。也就是说,如果类持有对IDisposable
类型的引用,则该类本身应实现IDisposable
。如果IAsyncResult
遵循该规则,那么它自己的Dispose
方法就可以决定需要处置哪个组成成员。
因此,除非有人有更令人信服的论据,否则我将停留在“总是称为Dispose”阵营中,因为要理解会有一些附带情况的情况主要是由不良的设计选择引起的。
真的很简单。我知道已经回答了,但是我会再试一次,但是会尽量简化。
通常不应该使用析构函数。它只运行.net希望它运行。它只会在垃圾回收周期之后运行。它可能永远不会在应用程序的生命周期内真正运行。出于这个原因,您永远不要在“必须”运行的析构函数中放置任何代码。当类运行时,您也不能依赖该类中的任何现有对象(它们可能已经被清理,因为不保证析构函数的运行顺序)。
只要您有一个对象创建需要清除的资源(即文件和图形句柄),就应使用IDisposible。实际上,许多人认为,由于上述原因,放置在析构函数中的任何内容都应放置在IDisposable中。
在执行终结器时,大多数类都将调用dispose,但这只是作为安全保护措施而已,绝不应该依赖它。完成IDisposable之后,您应该明确处置任何实现IDisposable的东西。如果确实实现IDisposable,则应在终结器中调用dispose。有关示例,请参见http://msdn.microsoft.com/zh-cn/library/system.idisposable.aspx。
这是另一篇很好的文章,它清除了IDisposable,GC和处置周围的一些薄雾。
using
构造轻松地做到这一点。