我已经在.NET中编程了四年(主要是C#)并且我广泛使用IDiposable,但我还没有找到终结者的需求。什么是终结者?
答案 0 :(得分:11)
终结器是确保正确清理某些内容的最后一次尝试,并且通常保留用于包装非托管资源的对象,例如不会被垃圾收集的非托管句柄等。
确实很难写出终结者。幸运的是(与IDisposable
不同),终结者不需要传播;所以如果你有一个ClassA
有一个终结器,一个ClassB
包裹ClassA
,那么ClassB
不需要终结器 - 但很可能都ClassA
并ClassB
将实施IDisposable
。
对于托管代码,IDisposable
通常就足够了。即使您没有正确清理,最终也会收集托管对象(假设它们已被释放)。
答案 1 :(得分:4)
终结器仅用于释放非托管资源,例如GDI位图句柄。如果您没有分配任何非托管资源,那么您不需要终结器。一般来说,触摸终结器中的任何托管对象是个坏主意,因为无法保证终结顺序。
使用终结器的另一个有用技术是声明在需要应用程序时已调用Dispose。这有助于捕获DEBUG构建中的编码错误:
void Dispose()
{
GC.SuppressFinalize(this);
}
#if DEBUG
~MyClass()
{
Debug.Fail("Dispose was not called.");
}
#endif
答案 2 :(得分:2)
终结器意味着释放不受垃圾收集器控制的资源的机制,如非托管句柄。虽然Dispose
可能会这样做,但不能保证消费者会调用它。
答案 3 :(得分:1)
终结者用于清理资源,如果他们没有处置。
IE,没有什么可以强制你调用Dispose(),但是垃圾收集器会自动调用终结器。
不应依赖此功能,因为无法保证何时(或如果)垃圾收集将到达您的对象。
答案 4 :(得分:1)
维基百科says:
...终结器是一段代码 确保某些必要的行动 在获得资源时采取...... 不再被使用[因为 拥有对象一直是垃圾 收集]
如果您在编写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;
就个人而言,我无法忍受复制粘贴,因此我倾向于将其包装在抽象类中以供重用。