(注意:该问题与Calling GC.SuppressFinalize() from within a finalizer相关,但不是重复项,因为此问题明确地专门针对无托管资源的情况,而这明确是关于同时拥有托管资源和非托管资源的。)
C#中的经典一次性模式大致如下:
public class MyClass : IDisposable {
bool alreadyDisposed = false;
void Dispose(bool calledFromDisposeMethod) {
if (!alreadyDisposed) {
alreadyDisposed = true;
if (calledFromDisposeMethod) {
GC.SuppressFinalize(this);
// Release _managed_ resources here
}
// Release _unmanaged_ resources here
}
}
public void Dispose() => Dispose(true);
~MyClass() => Dispose(false);
}
基本原理是,当MyClass
的一个实例被明确地处置(通过调用Dispose()
方法-可能但不一定通过使用using
)时,我们要释放所有资源,无论是托管资源还是非托管资源,而当实例被垃圾收集而尚未处置时,我们只想释放非托管资源,而将托管资源留在其他地方(例如让直到他们自己也被垃圾收集为止。
顺便说一句,请注意调用GC.SuppressFinalize(this)
,它告诉垃圾收集器,如果实例何时被垃圾收集,则无需调用终结器,因为Dispose()
已经被调用并被占用了。关心释放资源。由于使用了alreadyDisposed
标志,如果确实调用了终结器,则没有真正的危险,但这是不必要的,并且让垃圾收集器知道允许它跳过将实例放入终结队列中,从而有可能释放它(以及它引用的其他内容)更快。
但是现在我们仅拥有非托管资源的情况又如何呢?我希望可以找到以下更简单的模式:
public class MyClass : IDisposable {
bool alreadyDisposed = false;
void Dispose() {
if (!alreadyDisposed) {
alreadyDisposed = true;
// Release (unmanaged) resources here
GC.SuppressFinalize(this);
}
}
~MyClass() => Dispose();
}
再次注意呼叫GC.SuppressFinalize(this)
,其功能与上面相同。在这种情况下,它可能最终被终结器本身(间接)调用,但是据我所知,这样做没有害处。
这种形式的“一次性模式”似乎更简单,据我所知,完全可以满足需要-在不涉及托管资源的情况下。但是,我在任何地方都没有看到它,或者至少在任何地方都没有看到它宽容。
这种模式有意义吗,还是从根本上来说是有缺陷的?