为什么在析构函数中调用dispose(false)?

时间:2009-03-10 02:49:05

标签: c# 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 (!IsDisposed)
    {
      if (disposing)
      {
        //perform cleanup here
      }

      IsDisposed = true;
    }
  }

  ~MyObject()
  {
    Dispose(false);
  }

我理解dispose的作用,但我不明白为什么你想在析构函数中调用dispose(false)?如果你看一下这个定义它什么都不会做,那么为什么有人会编写这样的代码呢?根本没有从析构函数调用dispose是否有意义?

6 个答案:

答案 0 :(得分:43)

如果对象由于某种原因没有正确处理,则终结器用作后退。通常会调用Dispose()方法,它会删除终结器连接并将对象转换为垃圾收集器可以轻松删除的常规托管对象。

以下是MSDN中一个具有托管和非托管资源的类的示例。

请注意,只有disposing为真,才会清理托管资源,但始终会清除非托管资源。

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);
    }
}

答案 1 :(得分:18)

  

“这里的想法就是这样   Dispose(布尔值)知道它是否是   被要求进行明确的清理   (布尔值为true)与   由于垃圾收集而调用   (布尔值为false)。这个   区别是有用的,因为,何时   明确处置,   Dispose(布尔)方法可以安全地进行   使用引用类型执行代码   引用其他对象的字段   知道这些其他的肯定   对象尚未最终确定或   处置了。当布尔值是   false,Dispose(布尔)方法   不应该执行引用的代码   引用类型字段,因为那些   对象可能已经存在   已完成“。

“Dispose, Finalization, and Resource Management Design Guidelines”中有更多信息。

编辑:链接。

答案 2 :(得分:9)

C#中没有析构函数。这是一个终结者,这是另一回事。

区别在于您是否需要清理托管对象。您不想尝试在终结器中清理它们,因为它们本身可能已经完成。


我刚刚碰巧看了C#编程指南的Destructors页面。它表明我在上面的回答中弄错了。特别是,析构函数和终结符之间存在差异:

class Car
{
    ~Car()  // destructor
    {
        // cleanup statements...
    }
}

相当于

protected override void Finalize()
{
    try
    {
        // Cleanup statements...
    }
    finally
    {
        base.Finalize();
    }
}

答案 3 :(得分:3)

我认为混淆是因为在您的示例中您没有释放任何非托管资源。当通过垃圾收集调用dispose时,还需要释放它们,并且它们将在外部检查disposing。请参阅与releasing unmanaged resources相关的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);
   }

答案 4 :(得分:1)

在if(disposing)中,你应该在具有非托管资源的托管对象上调用dispose / close(例如数据库连接)。当调用终结器时,这些对象不再可访问,因此对象本身可以最终确定不需要对他们进行处理。最终确定的顺序也是未确定的,因此您可能会在已经处置的对象上调用dispose。

答案 5 :(得分:1)

以下示例演示如何创建实现IDisposable接口的资源类:https://msdn.microsoft.com/en-us/library/System.IDisposable.aspx

在Dispose(bool disposing)函数中:如果disposals equals为true,则代码直接或间接调用该方法。可以处理托管和非托管资源。如果disposals等于false,则运行时从终结器内部调用该方法,并且不应引用其他对象。只能处理非托管资源。