ID 一次性模式。我的终结器调用如何处置曾经免费的托管资源?

IDisposable Pattern. How does my finalizer's call of dispose ever free managed resources?

我有 Class 一个实现 Disposable 模式的 A,以释放非托管资源,例如取消订阅事件。 Class B 使用 Class A,但不会将其包装在 using {..} 块中,也不会显式调用 A.Dispose(true) 因此 A.dispose 在 A 的终结器中通过标准的 Dispose(false) 调用。但是通过将 bool 参数设置为 false,非托管资源将不会被清理,即不会取消订阅已订阅的事件。终结器不应该调用 Dispose(true) 还是 Class B 应该在某些时候显式调用 A.Dispose(true),例如在它自己的终结器中?

private bool _disposed = false; // To detect redundant calls

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                _promotionsSQLTableDependency.Stop();
                _awardsSQLTableDependency.Stop();
                _progressiveGeneratorService.OnProgressiveLevelsUpdate -= _progressiveUpdateHandler;
            }

            _disposed = true;
        }
    }

    ~PromotionHandler()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

dispose方法只能使用disposing参数来决定是否释放托管资源。非托管资源必须始终被释放。

protected virtual void Dispose(bool disposing)
{
    if (!_disposed)
    {
        if (disposing)
        {
            // Free managed resources
        }

        // always free unmanaged resources

        _disposed = true;
    }
}

如果 Dispose 调用是通过垃圾收集器发生的(=通过对终结器的调用)并且处理为 false,则不需要释放托管资源。垃圾回收器也会调用那些托管对象的Finalizer(可能更早)。

这就是the documentation says:

In the second overload, the disposing parameter is a Boolean that indicates whether the method call comes from a Dispose method (its value is true) or from a finalizer (its value is false).

The body of the method consists of two blocks of code:

  • A block that frees unmanaged resources. This block executes regardless of the value of the disposing parameter.

  • A conditional block that frees managed resources. This block executes if the value of disposing is true. The managed resources that it frees can include:

Managed objects that implement IDisposable. The conditional block can be used to call their Dispose implementation. If you have used a safe handle to wrap your unmanaged resource, you should call the SafeHandle.Dispose(Boolean) implementation here.

Managed objects that consume large amounts of memory or consume scarce resources. Freeing these objects explicitly in the Dispose method releases them faster than if they were reclaimed non-deterministically by the garbage collector.

If the method call comes from a finalizer (that is, if disposing is false), only the code that frees unmanaged resources executes. Because the order in which the garbage collector destroys managed objects during finalization is not defined, calling this Dispose overload with a value of false prevents the finalizer from trying to release managed resources that may have already been reclaimed.

implements the Disposable pattern in order to release unmanaged resources such as unsubscribing from events.

虽然取消订阅事件不是需要清理的非托管资源。

Class B uses Class A, but does not wrap it in a using {..} block nor explicity calls A.Dispose(true)

您应该将其视为程序中的错误。实施 IDisposable 的全部意义是因为该对象需要明确清理,所有者已完成。

But then by setting the bool parameter to false, the unmanaged resources will not be cleaned up,

但这些不是非托管资源,这就是为什么它们没有在 finally 块中清理的原因。

Shouldn't the finalizer be calling Dispose(true) or should Class B explicitly call A.Dispose(true) at some point such as in its own finalizer?

没有。您不应该在终结器中与托管对象进行交互。这样做不安全。由于您没有要在终结器中清理的非托管资源,因此您甚至不应该 拥有 终结器。