是的,您可以根据需要实现这两种方法。
一般来说,如果一个对象可以拥有受管理和未受管理的引用,则正确的模式是:
public class MyClass : IDisposable
{
~MyClass()
{
Dispose(false);
}
public void Dispose()
{
GC.SuppressFinalize(this);
Dispose(true);
}
public virtual void Dispose(bool disposing)
{
if(disposing)
{
}
}
}
但你可以根据自己的需求实现这个模式。例如,如果你没有任何未受管理的资源,并且你的类是密封的(所以你可以确定它永远不会使用任何未受管理的资源),那么你可以像这样实现:
public sealed class MyClass : IDisposable
{
public void Dispose()
{
}
}
而且不要考虑终结器。
在第一种模式中,GC.SuppressFinalize(this)
的作用是告诉垃圾回收器,在释放对象时不要调用终结器(即 ~MyClass()
方法):如果您已经显式调用了 Dispose()
,那么您已经调用了虚拟的 Dispose(bool)
函数,为什么还要再次调用呢?
问题在于,C# 中的终结器本身是非确定性的:您不知道它何时被调用...甚至不能保证它会被调用(尽管在正常清理期间如果之前没有调用过,它将被调用),这就是 IDisposable
存在的原因,它是一种以确定性方式释放对象所持有的托管引用并释放和释放其分配的非托管资源。
如果一个对象正在被 GC 释放,它所持有的所有托管引用也将被释放,因此在调用终结器时不需要清除托管引用。
但是,您的应用程序应该尽最大努力释放和释放任何非托管资源。
如果您忘记了调用 Dispose()
,则应该有最后的机会让它们被释放(当 GC 收集对象或在应用程序运行时进行最终清理时)。这就是为什么在正常模式下您还要实现终结器,并告诉它在之前未完成清理时清除非托管资源。
请注意,与流行观点相反,调用 Dispose()
并不特殊,它只是一个方法调用:如果您愿意,可以将其称为 FreeMyObject()
或 FooBar()
。它并不会使垃圾回收器释放任何内存。有一种使用 IDisposable
的模式,非常重要,以至于它拥有自己的语言语法结构(using
块),但它只是一种模式。您甚至可以完全不实现 IDisposable
来执行与 Dispose()
相同的操作。
base.Dispose()
。当然,没有人阻止你不调用基本方法并创建泄漏,但是再次强调,也没有任何防止您调用GC.SuppressFinalize(this)
、Thread.Abort()
或其他可能导致问题的类上的任何操作。 - Jcl