66

下面是一个典型的 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是否有意义?

4

6 回答 6

51

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

这是一个来自 MSDN 的示例,该类具有要清理的托管和非托管资源。

请注意,仅在为 true 时才清理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);
    }
}
于 2009-03-10T03:11:24.283 回答
19
于 2009-03-10T02:54:09.723 回答
9

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

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


我最近碰巧看了 C# Programming Guide 的Destructors页面。这表明我在上面的回答中是错误的。特别是,析构函数和终结函数之间存在区别:

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

相当于

protected override void Finalize()
{
    try
    {
        // Cleanup statements...
    }
    finally
    {
        base.Finalize();
    }
}
于 2009-03-10T02:53:25.153 回答
3
于 2009-03-10T03:10:42.913 回答
2

在 if(disposing) 内部,您应该对具有非托管资源(例如数据库连接)的托管对象调用 dispose/close。当调用终结器时,这些对象不再可访问,因此对象本身可以被终结,而您不需要需要对它们调用 dispose。此外,完成的顺序是未确定的,因此您可能会在已处理的对象上调用 dispose。

于 2009-03-10T02:59:48.197 回答
1

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

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

于 2018-05-21T10:07:31.907 回答