在 C# 中使用 IDisposable 和析构函数有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/339063/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the difference between using IDisposable vs a destructor in C#?
提问by Jordan Parmer
When would I implement IDispose on a class as opposed to a destructor? I read this article, but I'm still missing the point.
我什么时候在类上实现 IDispose 而不是析构函数?我读了这篇文章,但我仍然没有抓住重点。
My assumption is that if I implement IDispose on an object, I can explicitly 'destruct' it as opposed to waiting for the garbage collector to do it. Is this correct?
我的假设是,如果我在一个对象上实现 IDispose,我可以显式地“销毁”它,而不是等待垃圾收集器来执行它。这样对吗?
Does that mean I should always explicitly call Dispose on an object? What are some common examples of this?
这是否意味着我应该始终在对象上显式调用 Dispose?有哪些常见的例子?
采纳答案by Marc Gravell
A finalizer (aka destructor) is part of garbage collection (GC) - it is indeterminate when (or even if) this happens, as GC mainly happens as a result of memory pressure (i.e. need more space). Finalizers are usually only used for cleaning up unmanagedresources, since managed resources will have their own collection/disposal.
终结器(又名析构函数)是垃圾收集 (GC) 的一部分 - 不确定何时(甚至是否)发生这种情况,因为 GC 主要是由于内存压力(即需要更多空间)而发生的。终结器通常仅用于清理非托管资源,因为托管资源将有自己的收集/处置。
Hence IDisposable
is used to deterministicallyclean up objects, i.e. now. It doesn't collect the object's memory (that still belongs to GC) - but is used for example to close files, database connections, etc.
因此IDisposable
用于确定性地清理对象,即现在。它不收集对象的内存(仍然属于 GC) - 但用于例如关闭文件、数据库连接等。
There are lots of previous topics on this:
之前有很多关于此的主题:
Finally, note that it is not uncommon for an IDisposable
object to also have a finalizer; in this case, Dispose()
usually calls GC.SuppressFinalize(this)
, meaning that GC doesn't run the finalizer - it simply throws the memory away (much cheaper). The finalizer still runs if you forget to Dispose()
the object.
最后,请注意,IDisposable
对象也有终结器的情况并不少见。在这种情况下,Dispose()
通常调用GC.SuppressFinalize(this)
,这意味着 GC 不运行终结器 - 它只是将内存扔掉(便宜得多)。如果您忘记Dispose()
对象,终结器仍会运行。
回答by Igal Tabachnik
The role of the Finalize()
method is to ensure that a .NET object can clean up unmanaged resources when garbage collected. However, objects such as database connections or file handlers should be released as soon as possible, instead on relying on garbage collection. For that you should implement IDisposable
interface, and release your resources in the Dispose()
method.
该Finalize()
方法的作用是确保 .NET 对象可以在垃圾收集时清理非托管资源。但是,数据库连接或文件处理程序等对象应尽快释放,而不是依靠垃圾收集。为此,您应该实现IDisposable
接口,并在Dispose()
方法中释放您的资源。
回答by abatishchev
There is a very good description on MSDN:
MSDN上有一个很好的描述:
The primary use of this interface is to release unmanaged resources. The garbage collector automatically releases the memoryallocated to a managed object when that object is no longer used. However, it is not possible to predict when garbage collection will occur. Furthermore, the garbage collector has no knowledge of unmanaged resourcessuch as window handles, or open filesand streams.
Use the Dispose method of this interface to explicitly releaseunmanaged resources in conjunction with the garbage collector. The consumer of an objectcan call this method when the object is no longer needed.
此接口的主要用途是释放非托管资源。当某个对象不再使用时,垃圾收集器会自动释放分配给该对象的内存。但是,无法预测垃圾收集何时发生。此外,垃圾收集器不了解非托管资源,例如窗口句柄或打开的文件和流。
使用此接口的 Dispose 方法 与垃圾收集器一起显式释放非托管资源。当不再需要对象时,对象的 使用者可以调用此方法。
回答by DaEagle
It's pretty simple really. I know it's been answered but I'll try again but will try to keep it as simple as possible.
这真的很简单。我知道已经有人回答了,但我会再试一次,但会尽量保持简单。
A destructor should generally never be used. It is only run .net wants it to run. It will only run after a garbage collectoin cycle. It may never actually be run during the lifecycle of your application. For this reason, you should not ever put any code in a destructor that 'must' be run. You also can't rely on any existing objects within the class to exist when it runs (they may have already been cleaned up as the order in which destructors run in is not garanteed).
通常不应使用析构函数。它只是运行 .net 希望它运行。它只会在垃圾回收周期后运行。它可能永远不会在应用程序的生命周期中真正运行。出于这个原因,您永远不应将任何代码放入“必须”运行的析构函数中。您也不能依赖类中的任何现有对象在它运行时存在(它们可能已经被清除,因为析构函数的运行顺序没有保证)。
IDisposible should be used whenever you have an object that creates resources that need cleaning up (ie, file and graphics handles). In fact, many argue that anything you put in a destructor should be putin IDisposable due to the reasons listed above.
每当您有一个创建需要清理的资源(即文件和图形句柄)的对象时,就应该使用 IDisposible。事实上,由于上面列出的原因,许多人认为你放入析构函数的任何东西都应该放入 IDisposable。
Most classes will call dispose when the finalizer is executed but this is simply there as a safe guard and should never be relied upon. You should explicitly dispose anything that implements IDisposable when you're done with it. If you do implement IDisposable, you should call dispose in finalizer. See http://msdn.microsoft.com/en-us/library/system.idisposable.aspxfor an example.
大多数类会在执行终结器时调用 dispose ,但这只是作为一种安全保护,永远不应依赖。当你完成它时,你应该明确地处理任何实现 IDisposable 的东西。如果你确实实现了 IDisposable,你应该在终结器中调用 dispose。有关示例,请参见http://msdn.microsoft.com/en-us/library/system.idisposable.aspx。
回答by Jonathan Allen
The only thing that should be in a C# destructor is this line:
C# 析构函数中唯一应该包含的内容是这一行:
Dispose(False);
That's it. Nothing else should ever be in that method.
就是这样。在这种方法中不应该有其他任何东西。
回答by scope_creep
Here is another fine article which clears up some of the mist surrounding IDisposable, the GC and dispose.
这是另一篇很好的文章,它清除了围绕 IDisposable、GC 和 dispose 的一些迷雾。
回答by Brian Gideon
Your question regarding whether or not you should always call Dispose
is usually a heated debate. See thisblog for an interesting perspective from respected individuals in the .NET community.
你是否应该总是打电话Dispose
的问题通常是一场激烈的辩论。请参阅此博客,了解 .NET 社区中受人尊敬的个人的有趣观点。
Personally, I think Jeffrey Richter's position that calling Dispose
is not mandatory is incredibly weak. He gives two examples to justify his opinion.
就个人而言,我认为 Jeffrey Richter 认为呼叫Dispose
不是强制性的立场非常弱。他举了两个例子来证明他的观点。
In the first example he says calling Dispose
on Windows Forms controls is tedious and unnecessary in mainstream scenarios. However, he fails to mention that Dispose
actually is called automatically by control containers in those mainstream scenarios.
在第一个例子中,他说Dispose
在主流场景中调用Windows 窗体控件是乏味和不必要的。但是,他没有提到Dispose
在那些主流场景中实际上是由控制容器自动调用的。
In the second example he states that a developer may incorrectly assume that the instance from IAsyncResult.WaitHandle
should be aggressively disposed without realizing that the property lazily initializes the wait handle resulting in an unnecessary performance penalty. But, the problem with this example is that the IAsyncResult
itself does not adhere to Microsoft's own published guidelines for dealing with IDisposable
objects. That is if a class holds a reference to an IDisposable
type then the class itself should implement IDisposable
. If IAsyncResult
followed that rule then its own Dispose
method could make the decision regarding which of its constituent members needs disposing.
在第二个示例中,他指出开发人员可能错误地认为IAsyncResult.WaitHandle
应该积极处置实例 from ,而没有意识到该属性延迟初始化等待句柄,从而导致不必要的性能损失。但是,此示例的问题在于它IAsyncResult
本身不遵守 Microsoft 自己发布的处理IDisposable
对象的准则。也就是说,如果一个类持有对一个IDisposable
类型的引用,那么该类本身应该实现IDisposable
. 如果IAsyncResult
遵循该规则,则它自己的Dispose
方法可以决定其组成成员中的哪些需要处置。
So unless someone has a more compelling argument I am going to stay in the "always call Dispose" camp with the understanding that there are going to be some fringe cases that arise mostly out of poor design choices.
因此,除非有人有更令人信服的论点,否则我将留在“始终调用 Dispose”阵营中,并理解将有一些边缘案例主要是由于糟糕的设计选择而引起的。