29

这个答案中我发现,

当您的代码中使用了 Dispose/Finalize 模式时,清理 Finalize 方法中的非托管资源和 Dispose 方法中的托管资源。

后来我发现了这篇关于 finalize 和 dispose 的好文章,并对它们有了一个清晰的认识。文章有以下代码(第3页),用于解释概念:

class Test : IDisposable
{
    private bool isDisposed = false;

    ~Test()
    {
       Dispose(false);
    }

    protected void Dispose(bool disposing)
    {
       if (disposing)
       {
          // Code to dispose the managed resources of the class
       }
       // Code to dispose the un-managed resources of the class

       isDisposed = true;
    }

    public void Dispose()
    {
       Dispose(true);
       GC.SuppressFinalize(this);
    }
}

但在此之下,出现了相同的注释(我包含在这个问题的开头)。

Dispose/Finalize 模式 Microsoft 建议您在使用非托管资源时同时实现 Dispose 和 Finalize。正确的顺序是开发人员调用 Dispose。当对象被垃圾回收时,即使开发人员忽略显式调用 Dispose 方法,Finalize 实现仍将运行并且资源仍将被释放。Francesco Balena 在他的博客中写道:“仅当您的类型调用分配非托管资源(包括非托管内存)的非托管代码并返回您最终必须使用以释放资源的句柄时,才应使用 Dispose/Finalize 模式。dispose 和 finalize 都必须在它们处理或完成自己的成员后,通过调用其父对象各自的方法链接到它们的父对象”。 简单地说,当您的代码中使用了 Dispose/Finalize 模式时,清理 Finalize 方法中的非托管资源和 Dispose 方法中的托管资源。

现在我又困惑了。在整篇文章和代码示例中,都表明应该在Dispose(). 但是,那条评论的相关性是什么?

编辑:

经证实,这条线:

简而言之,当您的代码中使用了 Dispose/Finalize 模式时,清理 Finalize 方法中的非托管资源和 Dispose 方法中的托管资源

是错误的,我编辑了这个答案

4

2 回答 2

52

看它非常简单。

  1. 如果您正在处理非托管资源- 同时实现DisposeFinalize. Dispose开发人员一看到资源不再需要,就会调用它来释放资源。如果他们忘记调用,Dispose那么框架会在自己的 GC 周期中调用 finalize(通常会花费自己的甜蜜时间)。
  2. 如果您的对象在内部使用一次性对象-如果您创建并保留了对已实现且尚未处置Dispose()的任何类型对象的引用,则您实现。Dispose()
  3. 如果上述两种情况都不是(您不是在处理非托管资源,也不是您的对象在内部使用一次性对象) - 那么不要做任何事情。不实施Finalize也不Dispose

一些经典的例子:

System.IO.FileStream对象管理文件的锁/流句柄。所以它同时实现了 dispose 和 finalize。如果开发人员处理了它,那么其他程序可以立即访问它。如果他忘记处理它,那么框架将完成它并在其 GC 周期的后期关闭句柄。

System.Text.StringBuilder没有任何非托管资源。所以没有处置没有最终确定。

就模式而言,这意味着什么

// Code to dispose the managed resources of the class

是调用您在该类中作为组件拥有的任何 .NET 对象的 Dispose 方法

// Code to dispose the un-managed resources of the class

意味着关闭原始句柄和指针。这是带有示例的更新代码

class Test : IDisposable
{
  private bool isDisposed = false;

  ~Test()
  {
    Dispose(false);
  }

  protected void Dispose(bool disposing)
  {
    if (!isDisposed)
    {
      if (disposing)
      {
        // Code to dispose the managed resources of the class
        internalComponent1.Dispose();
        internalComponent2.Dispose();
      }

      // Code to dispose the un-managed resources of the class
      CloseHandle(handle);
      handle = IntPtr.Zero;   

      isDisposed = true;
    }
  }

  public void Dispose()
  {
    Dispose(true);
    GC.SuppressFinalize(this);
  }
}

这是一个解释它的老问题

于 2013-05-17T05:31:00.880 回答
5

如果 aFoo具有可以从确定性清理中受益的资源,但没有可以在终结器中有效清理的资源,则它应该实现IDisposable但不应覆盖Finalize或具有析构函数。如果一个类拥有多个资源,并且至少一个可以在终结器中清理,那么每个可以在终结器中清理的离散资源都应该封装到它自己的配备终结器/析构器的对象中(可以在受保护的嵌套类),并且包含这些资源的类应该包含对包装对象的引用。一旦完成,外部类将适合具有Dispose方法但没有终结器/析构函数的类的模式。

于 2013-05-17T21:12:04.867 回答