这里的终结器的目的只是为了防止内存泄漏(如果您意外地未显式调用Dispose
)。这也意味着,如果您希望在程序关闭时释放资源,您不必对对象进行处理,因为GC将被强制完成所有对象的终结和收集。
另一个相关的点是,在从终结器处处理对象时,需要略微不同的处理方式。
~MyClass()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(disposing)
{
if (!this.disposed)
{
if (disposing)
{
// Dispose managed resources here.
}
// Dispose unmanaged resources here.
}
this.disposed = true;
}
您不要在终结器中处理托管资源的原因是这样做实际上会创建对它们的强引用,这可能会阻止GC有效地执行其任务并收集它们。当然,应始终显式关闭/处理非托管资源(例如Win32句柄等),因为CLR对它们没有了解。
这主要是为了保护你自己。你无法控制你的类的最终用户会做什么。通过提供一个 finalizer 以及 Dispose 方法,即使用户忘记调用 Dispose() 或者错误地使用你的类,GC 也会“Dispose”你的对象,适当地释放你的资源。
当对象被垃圾回收时,会调用Finalizer方法。但需要显式调用Dispose方法。在下面的代码中,将调用Finalizer方法,但不会调用Dispose方法。
class Foo : IDisposable
{
public void Dispose()
{
Console.WriteLine("Disposed");
}
~Foo()
{
Console.WriteLine("Finalized");
}
}
...
public void Go()
{
Foo foo = new Foo();
}
IDisposable
对象是至关重要的。 - LukeH必须显式调用Dispose()方法或将对象放在using语句中以调用Dispose()方法来释放dispose方法。GC总是会调用finalizer,因此如果有需要在对象被处理之前发生的事情,则finalizer至少应该检查一下对象中的所有内容是否已清理干净。
尽可能避免在finalizer中清理对象,因为与事先释放它们(如调用dispose)相比,这会导致额外的工作量,但您应该始终在finalizer中检查是否有需要删除的对象。
(*) 那些被扩展为不对对象执行任何操作的内联代码的非虚方法可能会免除此规则,但Dispose通常是或调用虚方法。
Dispose
方法的托管块中。请考虑,如果是终结器调用Dispose
方法,您可以保证事件将作为终结的一部分立即被GC注销。 - Noldorin