IDisposable模式。我的终结者如何处置免费托管资源?

问题描述 投票:0回答:2

我有一个实现Disposable模式的A类,以释放非托管资源,例如取消订阅事件。 B类使用A类,但不将其包装在using {..}块中,也不用表达式调用A.Dispose(true),因此A.dispose通过标准的Dispose(false)调用在A的终结器中调用。但是,通过将bool参数设置为false,将不会清除非托管资源,即不会取消订阅订阅事件。终结器不应该调用Dispose(true),还是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);
    }
c# .net garbage-collection finalizer
2个回答
2
投票

实现Disposable模式以释放非托管资源,例如取消订阅事件。

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

B类使用A类,但不将它包装在using {..}块中,也不包括明确的调用A.Dispose(true)

您应该将其视为程序中的错误。实现IDisposable的重点是因为需要明确清理对象,并且所有者已完成它。

但是,通过将bool参数设置为false,将不会清除非托管资源,

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

终结器不应该调用Dispose(true),还是B类应该在某些时候显式调用A.Dispose(true),例如在它自己的终结器中?

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


0
投票

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

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

        // always free unmanaged resources

        _disposed = true;
    }
}

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

这就是the documentation says

在第二个重载中,disposing参数是一个布尔值,指示方法调用是来自Dispose方法(其值为true)还是来自终结器(其值为false)。

该方法的主体由两段代码组成:

  • 一个释放非托管资源的块。无论配置参数的值如何,都执行该块。
  • 释放托管资源的条件块。如果disposing的值为true,则执行此块。它释放的托管资源可以包括:

实现IDisposable的托管对象。条件块可用于调用其Dispose实现。如果您使用安全句柄来包装非托管资源,则应在此处调用SafeHandle.Dispose(Boolean)实现。

管理对象消耗大量内存或消耗稀缺资源。在Dispose方法中显式释放这些对象比它们被垃圾收集器非确定地回收它们更快地释放它们。

如果方法调用来自终结器(即,如果disposing为false),则只执行释放非托管资源的代码。由于未定义垃圾收集器在完成期间销毁托管对象的顺序,因此调用此Dispose重载值为false会阻止终结器尝试释放可能已经回收的托管资源。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.