C# 为什么在析构函数中调用dispose(false)?
下面是一个典型的dispose模式示例:C# 为什么在析构函数中调用dispose(false)?,c#,dispose,C#,Dispose,下面是一个典型的dispose模式示例: public bool IsDisposed { get; private set; } #region IDisposable Members public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!IsDisp
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);
}
我理解dispose的作用,但我不理解的是为什么要在析构函数中调用dispose(false)?如果你看一下定义,它将毫无用处,那么为什么会有人编写这样的代码呢?根本不从析构函数调用dispose,这有意义吗?C#中没有析构函数。这是一个终结器,这是另一回事 区别在于您是否需要清理托管对象。您不希望尝试在终结器中清理它们,因为它们本身可能已经终结
我最近碰巧看到了《C#编程指南》的一页。这表明我在上面的回答中错了。特别是,析构函数和终结器之间有一个区别:
class Car
{
~Car() // destructor
{
// cleanup statements...
}
}
相当于
protected override void Finalize()
{
try
{
// Cleanup statements...
}
finally
{
base.Finalize();
}
}
“这里的想法是
Dispose(布尔)知道它是否为
被调用进行显式清理
(布尔值为真)与被
由于垃圾收集而调用
(布尔值为false)。这是
区别是有用的,因为
被显式地处理后
Dispose(Boolean)方法可以安全地
使用引用类型执行代码
引用其他对象的字段
肯定知道这些
对象尚未最终确定或删除
已处理。当布尔值为
false,Dispose(布尔)方法
不应执行引用的代码
引用类型字段,因为
对象可能已被删除
最后定稿。”
有很多(很多!)更多的信息在网上
编辑:链接。在if(disposing)中,您应该对具有非托管资源(例如数据库连接)的托管对象调用dispose/close。当调用终结器时,这些对象不再是可访问的,因此对象本身可以被终结,您不需要对它们调用dispose。此外,终结的顺序尚未确定,因此您可能正在对已处置的对象调用dispose。我认为造成混淆的原因是,在您的示例中,您没有释放任何非托管资源。当通过垃圾收集调用dispose时,也需要释放它们,它们将被释放到检查
disposing
之外。请参阅有关的MSDN示例。另一个将/应该在检查之外发生的是对任何基类Dispose方法的调用
从引用的文章中:
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);
}
如果由于某种原因未正确处理对象,终结器将用作回退。通常会调用
Dispose()
方法,该方法删除终结器连接,并将对象转换为垃圾收集器可以轻松删除的常规托管对象
下面是来自MSDN的一个类的示例,该类具有要清理的托管和非托管资源
请注意,只有当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);
}
}
以下示例演示如何创建实现IDisposable接口的资源类:
在Dispose(bool disposing)函数中:如果disposing等于true,则代码已直接或间接调用该方法。可以释放托管和非托管资源。如果disposing等于false,则该方法已由运行时从终结器内部调用,您不应引用其他对象。只有非托管资源可以被释放。那么为什么不一起省略调用呢?但是释放是在If循环中完成的,当传递的参数为False时(从终结器中)不会执行If循环我的回答与我对另一个人的回答相同:那为什么要从终结器中调用它?@ryeguy,因为你实际上不应该自己实现终结器,除非你真的必须这样做。你的“更多信息”链接很棒!但是请注意,如果您没有非托管资源,那么
Dispose(false)
完全没有什么作用-因此您根本不需要终结器或Dispose(bool)
。我觉得标准模式过于复杂,无法满足几乎从未出现过的用例(当它们出现时,可能是个坏主意)。这里有一个我更喜欢的:@romkyns“[IDisposable]的主要用途是释放非托管资源。”()因此,如果您没有非托管资源,那么实现IDisposable的标准方法超出了您的需要也就不足为奇了。我不确定你所说的“几乎从不发生的用例”是什么意思——混合使用托管和非托管资源并不是一个模糊的用例。也就是说,我同意如果终结器没有做任何事情(因为你没有非托管资源),那么你就不需要它。像大多数模式一样(我想,像大多数东西一样),只有在有意义的地方使用它才有意义@TimGoodman的想法是,当一个类包含多个非托管资源时,几乎不可能提供预期的保证。阅读我发布的链接,它可能会说服你;写得很好。因此,建议永远不要在类中直接使用非托管资源,而是创建一个专用包装器,其唯一目的是处置非托管资源。那么您只有两种情况:一个包装类只有一个非托管资源,或者一个托管类只有托管IDisPoables可处置。@RomanStarkov的链接已移动到派生类的~Derived(){dispose(false);}
?