C# 为什么在析构函数中调用 dispose(false)?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/628752/
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
Why call dispose(false) in the destructor?
提问by ryeguy
What follows is a typical dispose pattern example:
以下是一个典型的处置模式示例:
public bool IsDisposed { get; private set; }
#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!IsDisposed)
{
if (disposing)
{
//perform cleanup here
}
IsDisposed = true;
}
}
~MyObject()
{
Dispose(false);
}
I understand what dispose does, but what I don't understand is why you would want to call dispose(false) in the destructor? If you look at the definition it would do absolutely nothing, so why would anyone write code like this? Wouldn't it make sense to just notcall dispose from the destructor at all?
我明白 dispose 的作用,但我不明白的是为什么要在析构函数中调用 dispose(false) ?如果您查看定义,它绝对不会做任何事情,那么为什么有人会编写这样的代码呢?根本不从析构函数调用 dispose难道没有意义吗?
采纳答案by Guffa
The finalizer is used as a fall-back if the object is not disposed properly for some reason. Normally the Dispose()
method would be called which removes the finalizer hookup and turns the object into a regular managed object that the garbage collector easily can remove.
如果由于某种原因未正确处置对象,则终结器将用作后备。通常Dispose()
会调用该方法来移除终结器连接并将对象转换为垃圾收集器可以轻松移除的常规托管对象。
Here is an example from MSDN of a class that has managed and unmanaged resources to clean up.
这是 MSDN 中的一个示例,该类具有要清理的托管和非托管资源。
Notice that the managed resources are only cleaned up if disposing
is true, but unmanaged resources is always cleaned up.
请注意,托管资源仅在disposing
为 true时才被清除,但非托管资源始终会被清除。
public class MyResource: IDisposable
{
// Pointer to an external unmanaged resource.
private IntPtr handle;
// Other managed resource this class uses.
private Component component = new Component();
// Track whether Dispose has been called.
private bool disposed = false;
// The class constructor.
public MyResource(IntPtr handle)
{
this.handle = handle;
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
private void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if(!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if(disposing)
{
// Dispose managed resources.
component.Dispose();
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
CloseHandle(handle);
handle = IntPtr.Zero;
// Note disposing has been done.
disposed = true;
}
}
// Use interop to call the method necessary
// to clean up the unmanaged resource.
[System.Runtime.InteropServices.DllImport("Kernel32")]
private extern static Boolean CloseHandle(IntPtr handle);
// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~MyResource()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
}
回答by John Saunders
There are no destructors in C#. That's a Finalizer, which is a different thing.
C# 中没有析构函数。那是一个终结器,这是另一回事。
The distinction is whether you need to clean up managed objects or not. You don't want to try to clean them up in the finalizer, as they may themselves have been finalized.
区别在于您是否需要清理托管对象。您不想尝试在终结器中清理它们,因为它们本身可能已被终结。
I just recently happened to look at the Destructorspage of the C# Programming Guide. It shows that I was mistaken in my answer, above. In particular, there is a difference between destructor and finalizer:
我最近偶然看到了 C# 编程指南的析构函数页面。这表明我在上面的回答中弄错了。尤其是析构函数和终结器之间的区别:
class Car
{
~Car() // destructor
{
// cleanup statements...
}
}
is equivalent to
相当于
protected override void Finalize()
{
try
{
// Cleanup statements...
}
finally
{
base.Finalize();
}
}
回答by stuartd
"The idea here is that Dispose(Boolean) knows whether it is being called to do explicit cleanup (the Boolean is true) versus being called due to a garbage collection (the Boolean is false). This distinction is useful because, when being disposed explicitly, the Dispose(Boolean) method can safely execute code using reference type fields that refer to other objects knowing for sure that these other objects have not been finalized or disposed of yet. When the Boolean is false, the Dispose(Boolean) method should not execute code that refer to reference type fields because those objects may have already been finalized."
“这里的想法是 Dispose(Boolean) 知道它是被调用来执行显式清理(布尔值为真)还是由于垃圾收集而被调用(布尔值为假)。这种区别很有用,因为当被处置时明确地,Dispose(Boolean) 方法可以使用引用其他对象的引用类型字段安全地执行代码,知道这些其他对象尚未最终确定或处置。当 Boolean 为 false 时,Dispose(Boolean) 方法应该不执行引用引用类型字段的代码,因为这些对象可能已经完成。”
There's much more info in the “Dispose, Finalization, and Resource Management Design Guidelines”.
“处置、终结和资源管理设计指南”中有更多信息。
Edit: link.
编辑:链接。
回答by ggf31416
Inside the if(disposing) you are supposed to call dispose/close on managed objects that have unmanaged resources (e.g. database connections).When the finalizer is called these objects are not longer reachable so the objects themselves can be finalized and you don't need to call dispose on them. Also the order of finalization is undeterminated so you may be calling dispose on already disposed objects.
在 if(disposing) 中,您应该在具有非托管资源(例如数据库连接)的托管对象上调用 dispose/close。当调用终结器时,这些对象不再可访问,因此对象本身可以被终结,而您不会需要调用他们的处置。此外,最终确定的顺序是不确定的,因此您可能会在已处置的对象上调用 dispose。
回答by tvanfosson
I think the confusion is due to the fact that in your example you aren't releasing any unmanaged resources. These also need to be released when dispose is called via garbage collection and they would be released outsidethe check for disposing
. See the MSDN example relating to releasing unmanaged resources. The other that that would/should happen outside the check is a call to any base class Dispose method.
我认为混淆是由于在您的示例中您没有释放任何非托管资源。这些也需要在通过垃圾收集调用 dispose 时释放,并且它们将在检查 for之外释放disposing
。请参阅与释放非托管资源相关的 MSDN 示例。另一个将/应该发生在检查之外的是对任何基类 Dispose 方法的调用。
From the quoted article:
从引用的文章:
protected override void Dispose(bool disposing)
{
if (disposing)
{
// Release managed resources.
}
// Release unmanaged resources.
// Set large fields to null.
// Call Dispose on your base class.
base.Dispose(disposing);
}
回答by Trung Nguy?n Vi?t
The following example demonstrates how to create a resource class that implements the IDisposable interface: https://msdn.microsoft.com/en-us/library/System.IDisposable.aspx
以下示例演示了如何创建实现 IDisposable 接口的资源类:https: //msdn.microsoft.com/en-us/library/System.IDisposable.aspx
In Dispose(bool disposing) function: If disposing equals true, the method has been called directly or indirectly by your code. Managed and unmanaged resources can be disposed. If disposing equals false, the method has been called by the runtime from inside the finalizer and you should not reference other objects. Only unmanaged resources can be disposed.
在 Dispose(bool disposing) 函数中:如果 disposing 等于 true,则该方法已被您的代码直接或间接调用。可以处置托管和非托管资源。如果 disposing 等于 false,则该方法已由运行时从终结器内部调用,您不应引用其他对象。只能处理非托管资源。