在 C# 中使用 IDisposable 与析构函数有什么区别?
-
19-08-2019 - |
题
我什么时候应该在类上实现 IDispose 而不是析构函数?我读 本文, ,但我仍然没有抓住重点。
我的假设是,如果我在一个对象上实现 IDispose,我可以显式地“破坏”它,而不是等待垃圾收集器来执行它。它是否正确?
这是否意味着我应该始终在对象上显式调用 Dispose?这方面有哪些常见的例子?
解决方案
终结器(又称析构函数)是垃圾收集 (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希望它运行。它只是将垃圾collectoin周期之后运行。它可能从来没有实际应用程序的生命周期中运行。出于这个原因,你不应该没有把任何代码的析构函数“必须”运行。您也可以不依赖于类中的任何现有对象存在时,它运行(它们可能已经被清理在其析构函数运行中没有保证下,顺序)。
IDisposible应该只要你有创建需要清理(即文件和图形处理)资源的对象使用。事实上,许多人认为,任何事情你把析构函数应该是普京的IDisposable由于上面列出的原因。
大多数类将调用执行终结处置的时候,但这仅仅是存在的安全防范和不应依赖该等资料。你应该明确地处置任何实现IDisposable当你用它做。如果你实现IDisposable,你应该叫处置中终结。请参见 http://msdn.microsoft.com/en-us/library /system.idisposable.aspx 一个例子。
下面是另一个它清除了一些周围的IDisposable,GC和雾的细条处理。