我已经在 .NET 中编程了四年(主要是 C#),并且我广泛使用 IDiposable,但我还没有发现需要终结器。终结者有什么用?
5 回答
终结器是确保正确清理某些内容的最后尝试,通常保留给包装非托管资源的对象,例如不会被垃圾收集的非托管句柄等。
编写终结器确实很少见。幸运的是(与 不同IDisposable
),终结器不需要传播;因此,如果您有一个ClassA
带有终结器的 a 和一个ClassB
which wraps ClassA
,则ClassB
不需要终结器 - 但很可能两者都ClassA
将ClassB
实现IDisposable
.
对于托管代码,IDisposable
通常就足够了。即使您没有正确清理,最终托管对象也会被收集(假设它们已被释放)。
终结器仅用于释放非托管资源,例如 GDI 位图句柄。如果您不分配任何非托管资源,那么您不需要终结器。一般来说,在终结器中触摸任何托管对象都是一个坏主意,因为不能保证终结的顺序。
另一种使用终结器的有用技术是在应用程序需要这样做时断言 Dispose 已被调用。这可以帮助捕获 DEBUG 构建中的编码错误:
void Dispose()
{
GC.SuppressFinalize(this);
}
#if DEBUG
~MyClass()
{
Debug.Fail("Dispose was not called.");
}
#endif
终结器是一种释放不受垃圾收集器控制的资源的机制,例如非托管句柄。虽然Dispose
可能会这样做,但不能保证消费者会调用它。
终结器用于清理未处理的资源。
IE,没有任何东西强制你调用 Dispose(),但是垃圾收集器会自动调用终结器。
不应依赖此功能,因为无法保证垃圾收集何时(或是否)到达您的对象。
维基百科说:
...终结器是一段代码,可确保在获取的资源...不再使用时采取某些必要的操作[因为拥有的对象已被垃圾收集]
如果您在编写 IDisposables 时没有使用终结器,那么您很可能会发生内存泄漏,因为无法保证所有者实际上会调用 Dispose()。
MS 自己建议您将与此类似的内容写入您的实施者:
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;
就个人而言,我无法忍受复制粘贴,所以我倾向于将其包装在一个抽象类中以供重用。