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

时间:2019-04-12 16:00:57

标签: c# .net garbage-collection finalizer

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

  this.ngZone.run(() => {
        this.store.dispatch(new ResetSettingsProgressValue(setting));
        this.store.dispatch(new LoadSettingsProgressValue(setting));
  });

2 个答案:

答案 0 :(得分:2)

  

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

退订事件不是需要清除的非托管资源。

  

B类使用A类,但不将其包装在using {..}块中,也不显式调用A.Dispose(true)

您应该将其视为程序中的错误。实施IDisposable的全部目的是因为该对象需要由所有者来明确清理。

  

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

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

  

终结器不应该调用Dispose(true)还是B类应该在某个时刻(例如在其自身的终结器中)显式调用A.Dispose(true)?

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

答案 1 :(得分:0)

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

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

        // always free unmanaged resources

        _disposed = true;
    }
}

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

这就是the documentation says

  

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

     

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

     
      
  • 释放非托管资源的块。不管dispose参数的值如何,该块都会执行。

  •   
  • 一个释放托管资源的条件块。如果dispose的值为true,则执行此块。托管资源   免费包括:

  •   
     

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

     

消耗大量内存或消耗稀缺资源的托管对象。在“处置”中显式释放这些对象   方法释放它们的速度比回收它们的速度快   由垃圾收集器不确定地确定。

     

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