2024-09-20 10:00:04

Finalize vs Dispose

为什么有些人使用Finalize方法而不是Dispose方法?

在什么情况下你会使用Finalize方法而不是Dispose方法,反之亦然?


当前回答

99%的情况下,你都不需要担心。但是,如果你的对象持有对非托管资源的引用(例如,窗口句柄,文件句柄),你需要为托管对象提供一种释放这些资源的方法。Finalize对释放资源进行隐式控制。它由垃圾回收器调用。Dispose是一种对资源释放进行显式控制的方法,可以直接调用。

关于垃圾收集的主题还有很多很多需要学习,但这只是一个开始。

其他回答

99%的情况下,你都不需要担心。但是,如果你的对象持有对非托管资源的引用(例如,窗口句柄,文件句柄),你需要为托管对象提供一种释放这些资源的方法。Finalize对释放资源进行隐式控制。它由垃圾回收器调用。Dispose是一种对资源释放进行显式控制的方法,可以直接调用。

关于垃圾收集的主题还有很多很多需要学习,但这只是一个开始。

这是我知道的最好的例子。

 public abstract class DisposableType: IDisposable
  {
    bool disposed = false;

    ~DisposableType()
    {
      if (!disposed) 
      {
        disposed = true;
        Dispose(false);
      }
    }

    public void Dispose()
    {
      if (!disposed) 
      {
        disposed = true;
        Dispose(true);
        GC.SuppressFinalize(this);
      }
    }

    public void Close()
    {
      Dispose();
    }

    protected virtual void Dispose(bool disposing)
    {
      if (disposing) 
      {
        // managed objects
      }
      // unmanaged objects and resources
    }
  }

摘要如下-

You write a finalizer for your class if it has reference to unmanaged resources and you want to make sure that those unmanaged resources are released when an instance of that class is garbage collected automatically. Note that you can't call the Finalizer of an object explicitly - it's called automatically by the garbage collector as and when it deems necessary. On the other hand, you implement the IDisposable interface(and consequently define the Dispose() method as a result for your class) when your class has reference to unmanaged resources, but you don't want to wait for the garbage collector to kick in (which can be anytime - not in control of the programmer) and want to release those resources as soon as you are done. Thus, you can explicitly release unmanaged resources by calling an object's Dispose() method.

另外,另一个区别是——在Dispose()实现中,您也应该释放托管资源,而在Finalizer中不应该这样做。这是因为对象引用的托管资源很可能在准备完成之前就已经被清理了。

对于使用非托管资源的类,最佳实践是同时定义Dispose()方法和Finalizer,以便在开发人员忘记显式地释放对象时作为备用方案使用。两者都可以使用共享的方法来清理托管和非托管资源:-

class ClassWithDisposeAndFinalize : IDisposable
{
    // Used to determine if Dispose() has already been called, so that the finalizer
    // knows if it needs to clean up unmanaged resources.
     private bool disposed = false;

     public void Dispose()
     {
       // Call our shared helper method.
       // Specifying "true" signifies that the object user triggered the cleanup.
          CleanUp(true);

       // Now suppress finalization to make sure that the Finalize method 
       // doesn't attempt to clean up unmanaged resources.
          GC.SuppressFinalize(this);
     }
     private void CleanUp(bool disposing)
     {
        // Be sure we have not already been disposed!
        if (!this.disposed)
        {
             // If disposing equals true i.e. if disposed explicitly, dispose all 
             // managed resources.
            if (disposing)
            {
             // Dispose managed resources.
            }
             // Clean up unmanaged resources here.
        }
        disposed = true;
      }

      // the below is called the destructor or Finalizer
     ~ClassWithDisposeAndFinalize()
     {
        // Call our shared helper method.
        // Specifying "false" signifies that the GC triggered the cleanup.
        CleanUp(false);
     }

c#中Finalize和Dispose方法的区别。

GC调用finalize方法来回收非托管资源(如文件操作、windows api、网络连接、数据库连接),但GC调用它的时间不固定。它是由GC隐式调用的,这意味着我们对它没有低级控制。

处理方法:当我们从代码中调用它时,我们对它有低级别的控制。我们可以在觉得不可用的时候回收非托管资源。我们可以通过实现IDisposal模式来实现这一点。

finalizer方法在对象被垃圾收集时被调用,并且您无法保证何时会发生这种情况(您可以强制执行,但这会影响性能)。

另一方面,Dispose方法应该由创建类的代码调用,以便在代码处理完对象后立即清理和释放已获得的任何资源(非托管数据、数据库连接、文件句柄等)。

标准实践是实现IDisposable和Dispose,这样就可以在using语句中使用对象。例如使用(var foo = new MyObject()){}。在终结器中,你调用Dispose,以防调用代码忘记释放你。