什么是终结器的作用?

9

我已经使用.NET编程四年了(主要是C#),我广泛地使用IDisposable,但我还没有找到需要使用终结器的情况。那么终结器有什么作用呢?


5
顺便提一下,我是英国人,发现习惯用 z 而不是 s 拼写 finalize 和 initialize 是一个非常好的主意。否则,当你在文档中搜索它们时,你永远也找不到这些该死的东西! - Steve Jessop
1
@onebyone - 同上。同样地,颜色...它曾经让我感到烦恼,但现在我只把它们视为行业的技术术语,并完成工作 ;-p - Marc Gravell
我一直在努力训练自己——我在文档和公共代码中使用它,但我就是无法在“现实生活”中做到。 - open-collar
5个回答

12

Finalizer(终结器)是一种最后的手段,用于确保正确清理某些东西,通常用于封装非托管资源的对象,如非托管句柄等,这些资源不会被垃圾回收。

编写finalizer的情况确实很少。幸运的是(与IDisposable不同),finalizer不需要传播;因此,如果您有一个带有finalizer的ClassA和包装ClassAClassB,那么ClassB不需要finalizer-但两个类都很可能实现IDisposable

对于托管代码,IDisposable通常足够了。即使您没有正确清理,最终托管对象也会被收集(假设它们被释放了)。


4

Finalizers只用于释放像GDI位图句柄这样的非托管资源。如果您没有分配任何非托管资源,则不需要使用finalizer。通常,在finalizer中触及任何托管对象都是一个坏主意,因为finalization的顺序不能保证。

使用finalizer的另一种有用技术是在需要应用程序调用Dispose时断言已调用Dispose。这可以帮助在DEBUG版本中捕获编码错误:

void Dispose()
{
  GC.SuppressFinalize(this);
}
#if DEBUG
~MyClass()
{
  Debug.Fail("Dispose was not called.");
}
#endif

2

Finalizers(终结器)是一种释放不受垃圾回收控制的资源(例如未经管理的句柄)的机制。虽然Dispose(释放)可能会这样做,但不能保证使用者会调用它。


1

维基百科说道

……一个终结器是一段代码,确保在已获得的资源不再被使用(因为拥有对象已被垃圾回收)时采取某些必要的操作。

如果你在编写IDisposable时没有使用终结器,那么很可能会出现内存泄漏,因为不能保证所有者实际上会调用Dispose()。

微软自己建议您将类似于以下内容的代码编写到您的实现中:

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

    protected virtual void Dispose(bool disposing)
    {
        if (!this.isDisposed)
        {
            if (disposing)
            {
                GC.SuppressFinalize(this);
            }
        }
        //Dispose of resources here
        this.isDisposed = true;
    }

    ~DisposableSafe()
    {
        this.Dispose(false);
    }

    private bool isDisposed = false;

个人而言,我无法忍受复制粘贴,因此我倾向于将其封装在一个抽象类中以便重用。


除非你的类直接处理非托管资源,否则你可能不需要一个析构函数。托管资源应该最终由GC处理,无论用户是否调用Dispose方法。 - LukeH
这就是让我写“可能”而不是“大概”的原因,并且我对此感到担心。但无论如何,这并不完全正确。如果您的类实现了其他IDisposable,则还有责任调用其Dispose()方法。从MSDN上来看,“此接口的主要用途是释放非托管资源。” - annakata

1

最终器用于在资源未被处理时清理其资源。

也就是说,没有任何强制要求您调用Dispose()函数,但最终器会由垃圾回收自动调用。

不能依赖此功能,因为无法保证垃圾回收何时(或是否)到达您的对象。


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