113

我什么时候在类上实现 IDispose 而不是析构函数?我读了这篇文章,但我仍然没有抓住重点。

我的假设是,如果我在一个对象上实现 IDispose,我可以显式地“破坏”它,而不是等待垃圾收集器去做。它是否正确?

这是否意味着我应该始终明确地在对象上调用 Dispose?有哪些常见的例子?

4

7 回答 7

143

终结器(又名析构函数)是垃圾回收 (GC) 的一部分 - 它何时(甚至是否)发生是不确定的,因为 GC 主要是由于内存压力(即需要更多空间)而发生的。终结器通常仅用于清理非托管资源,因为托管资源将有自己的收集/处置。

因此IDisposable用于确定性地清理对象,即现在。它不收集对象的内存(仍然属于 GC) - 但用于例如关闭文件、数据库连接等。

以前有很多关于此的主题:

IDisposable最后,请注意对象也有终结器的情况并不少见。在这种情况下,Dispose()通常调用GC.SuppressFinalize(this),这意味着 GC 不运行终结器 - 它只是将内存扔掉(便宜得多)。如果您忘记Dispose()了对象,终结器仍然会运行。

于 2008-12-03T23:09:46.173 回答
27

Finalize()方法的作用是确保 .NET 对象在垃圾收集时可以清理非托管资源。但是,应该尽快释放数据库连接或文件处理程序等对象,而不是依赖垃圾收集。为此,您应该实现接口,并在方法IDisposable中释放资源。Dispose()

于 2008-12-03T23:10:59.667 回答
9

MSDN上有一个很好的描述:

该接口的主要用途是释放非托管资源。当不再使用该对象时,垃圾收集器会自动释放分配给托管对象的内存。但是,无法预测何时会发生垃圾收集。此外,垃圾收集器不了解非托管资源 ,例如窗口句柄或打开的文件和流。

使用此接口的 Dispose 方法与垃圾收集器一起显式释放 非托管资源。当不再需要对象时,对象的 使用者可以调用此方法。

于 2008-12-03T23:14:19.067 回答
9

唯一应该在 C# 析构函数中的是这一行:

Dispose(False);

就是这样。这种方法不应该有其他任何东西。

于 2008-12-04T00:48:06.413 回答
5

你是否应该总是打电话Dispose的问题通常是一场激烈的辩论。请参阅博客,了解 .NET 社区中受人尊敬的个人的有趣观点。

就个人而言,我认为 Jeffrey Richter 认为呼叫Dispose不是强制性的立场是非常薄弱的​​。他举了两个例子来证明他的观点。

在第一个示例中,他说Dispose在主流场景中调用 Windows 窗体控件是乏味且不必要的。但是,他没有提到Dispose实际上是在那些主流场景中由控制容器自动调用的。

在第二个示例中,他指出开发人员可能错误地认为IAsyncResult.WaitHandle应该积极处置实例 from,而没有意识到该属性会延迟初始化等待句柄,从而导致不必要的性能损失。但是,这个例子的问题在于它IAsyncResult本身并没有遵守微软自己发布的处理IDisposable对象的指南。也就是说,如果一个类拥有对某个IDisposable类型的引用,那么该类本身应该实现IDisposable。如果IAsyncResult遵循该规则,那么它自己的Dispose方法可以决定哪些组成成员需要处置。

因此,除非有人有更令人信服的论点,否则我将留在“总是调用 Dispose”阵营,并理解将有一些边缘案例主要是由于糟糕的设计选择而出现的。

于 2009-09-09T15:21:23.297 回答
3

这真的很简单。我知道它已被回答,但我会再试一次,但会尽量保持简单。

通常不应该使用析构函数。它只是运行.net 想要它运行。它只会在垃圾回收周期后运行。它可能永远不会在您的应用程序的生命周期中真正运行。出于这个原因,您不应该将任何代码放入“必须”运行的析构函数中。您也不能依赖类中的任何现有对象在运行时存在(它们可能已经被清理,因为不保证析构函数的运行顺序)。

只要您有一个创建需要清理的资源(即文件和图形句柄)的对象,就应该使用 IDisposible。事实上,许多人认为,由于上面列出的原因,你放入析构函数中的任何东西都应该放入 IDisposable。

大多数类在执行终结器时都会调用 dispose ,但这只是作为安全防护,永远不应依赖。完成后,您应该明确处置任何实现 IDisposable 的东西。如果你确实实现了 IDisposable,你应该在终结器中调用 dispose。有关示例,请参见http://msdn.microsoft.com/en-us/library/system.idisposable.aspx 。

于 2008-12-03T23:19:49.273 回答
0

这是另一篇很好的文章,它清除了 IDisposable、GC 和 dispose 周围的一些迷雾。

Chris Lyons WebLog 揭秘处置

于 2009-09-09T14:57:53.850 回答