在C#中使用IDisposable与析构函数有什么区别?

Jor*_*mer 95 .net c# dispose destructor

我何时在类上实现IDispose而不是析构函数?我读过这篇文章,但我仍然忽略了这一点.

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

这是否意味着我应该总是在对象上显式调用Dispose?这有什么常见的例子?

Mar*_*ell 121

终结器(也称为析构函数)是垃圾收集(GC)的一部分 - 当发生这种情况时(或者即使发生这种情况)它是不确定的,因为GC主要是由于内存压力(即需要更多空间)而发生的.终结器通常仅用于清理非托管资源,因为托管资源将有自己的收集/处置.

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

以前有很多主题:

最后,请注意,IDisposable对象也有一个终结器并不罕见; 在这种情况下,Dispose()通常是调用GC.SuppressFinalize(this),这意味着GC不会运行终结器 - 它只是抛弃内存(便宜得多).如果忘记Dispose()对象,终结器仍会运行.

  • 还有一件事要说.不要在你的课程中添加终结者,除非你真的需要一个.如果你添加一个终结器(析构函数),GC必须调用它(甚至是一个空的终结器)并调用它,对象将始终在第1代垃圾收集中存活.这将阻碍和减慢GC.Marc在上面的代码中称之为SuppressFinalize (25认同)
  • @黑暗是的; 因为管理链中的6个级别可能是不受管理的,需要及时清理 (2认同)

Iga*_*nik 23

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


aba*_*hev 9

MSDN上有一个非常好的描述:

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

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


Jon*_*len 8

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

Dispose(False);
Run Code Online (Sandbox Code Playgroud)

而已.在该方法中不应该有任何其他东西.

  • 这是Microsoft在.NET文档中提出的设计模式,但是当您的对象不是IDisposable时不要使用它.http://msdn.microsoft.com/en-us/library/fs2xkftw%28v=vs.110%29.aspx (3认同)

Bri*_*eon 5

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

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

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

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

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