(注意:这个问题与Calling GC.SuppressFinalize() from inside a finalizer有关,但不是重复的,因为这个问题明确地专门针对no managed resources的情况,而这个问题明确地涉及同时拥有托管和非托管资源的情况资源。)
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
),那么我们想要释放所有资源,无论是托管还是非托管,而当实例被垃圾收集而没有已经被处理掉了,那么我们只想释放非托管资源,将托管资源留给其他地方处理(例如,让它们一直存在,直到它们本身也被垃圾收集)。
顺便说一句,注意 call 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();
}
再次注意 call GC.SuppressFinalize(this)
,它具有与上面相同的功能。在这种情况下,它可能最终会被终结器本身(间接)调用,但据我所知,这并没有什么坏处。
这种一次性模式的形式看起来更简单,而且据我所知,在不涉及托管资源的情况下完全足够了。然而,我还没有在任何地方看到它,或者至少我没有看到它在任何地方被宽恕。
这种模式是否有意义,还是存在根本缺陷?