0

(注意:这个问题与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),它具有与上面相同的功能。在这种情况下,它可能最终会被终结器本身(间接)调用,但据我所知,这并没有什么坏处。

这种一次性模式的形式看起来更简单,而且据我所知,在不涉及托管资源的情况下完全足够了。然而,我还没有在任何地方看到它,或者至少我没有看到它在任何地方被宽恕

这种模式是否有意义,还是存在根本缺陷?

4

0 回答 0