Dispose、Finalize以及SuppressFinalize方法

3

我可以在同一个类中实现这两个方法吗?

public class MyClass : IDisposable
{
  // some implementation
  // if i missed to call Dispose() method;
  ~MyClass()
  {
  // it means, clear all does not mananage resources 
  // but dont use Dispose() method 
  }
  public void Dispose()
  {
   // clear resources
   // if i call this method will i can do this:
   GC.SuppressFinalize()
   // it means dont use Finalizw method for this object
  }
}

我理解得没错吧?因为我不太懂 GC.SuppressFinalize() 方法。

1个回答

7

是的,您可以根据需要实现这两种方法。

一般来说,如果一个对象可以拥有受管理和未受管理的引用,则正确的模式是:

public class MyClass : IDisposable
{
  ~MyClass()
  {
    Dispose(false);
  }
  public void Dispose()
  {
    GC.SuppressFinalize(this); 
    Dispose(true);
  }
  public virtual void Dispose(bool disposing)
  {
    if(disposing)
    {
      // clear MANAGED references
    }
    // free UNMANAGED resources
  }
}

但你可以根据自己的需求实现这个模式。例如,如果你没有任何未受管理的资源,并且你的类是密封的(所以你可以确定它永远不会使用任何未受管理的资源),那么你可以像这样实现:

public sealed class MyClass : IDisposable
{
  public void Dispose()
  {
    // release managed references
  }
}

而且不要考虑终结器。

在第一种模式中,GC.SuppressFinalize(this) 的作用是告诉垃圾回收器,在释放对象时不要调用终结器(即 ~MyClass() 方法):如果您已经显式调用了 Dispose(),那么您已经调用了虚拟的 Dispose(bool) 函数,为什么还要再次调用呢?

问题在于,C# 中的终结器本身是非确定性的:您不知道它何时被调用...甚至不能保证它会被调用(尽管在正常清理期间如果之前没有调用过,它将被调用),这就是 IDisposable 存在的原因,它是一种以确定性方式释放对象所持有的托管引用并释放和释放其分配的非托管资源。

如果一个对象正在被 GC 释放,它所持有的所有托管引用也将被释放,因此在调用终结器时不需要清除托管引用。

但是,您的应用程序应该尽最大努力释放和释放任何非托管资源。

如果您忘记了调用 Dispose(),则应该有最后的机会让它们被释放(当 GC 收集对象或在应用程序运行时进行最终清理时)。这就是为什么在正常模式下您还要实现终结器,并告诉它在之前未完成清理时清除非托管资源。

请注意,与流行观点相反,调用 Dispose() 并不特殊,它只是一个方法调用:如果您愿意,可以将其称为 FreeMyObject()FooBar()。它并不会使垃圾回收器释放任何内存。有一种使用 IDisposable 的模式,非常重要,以至于它拥有自己的语言语法结构(using 块),但它只是一种模式。您甚至可以完全不实现 IDisposable 来执行与 Dispose() 相同的操作。


为什么方法public virtual void Dispose(bool disposing)被标记为虚拟的?这是否意味着在子类中我们可以重写它,忘记释放基类的某些内存,并创建内存泄漏? - Misha Huziuk
@MishaHuziuk 的想法是派生类应该重写方法,清理自己的资源(在派生类中添加的资源),然后调用 base.Dispose()。当然,没有人阻止你不调用基本方法并创建泄漏,但是再次强调,也没有任何防止您调用 GC.SuppressFinalize(this)Thread.Abort() 或其他可能导致问题的类上的任何操作。 - Jcl
明白了。谢谢! - Misha Huziuk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接