【问题标题】:Should I implement IDisposable when class has IDisposable member but no unmanaged resources?当类具有 IDisposable 成员但没有非托管资源时,我应该实现 IDisposable 吗?
【发布时间】:2016-06-21 01:59:08
【问题描述】:

MSDN 文档和 StackOverflow 上的许多答案不遗余力地讨论正确实现 IDisposable,例如MSDN IDisposable, MSDN Implementing IDisposable, An excellent StackOverflow Q&A

但是,它们似乎都没有涵盖我拥有的更常见的用例:当我的班级有一个比一种方法寿命更长的IDisposable 成员时该怎么办?例如

  class FantasticFileService
  {
    private FileSystemWatcher fileWatch; // FileSystemWatcher is IDisposable

    public FantasticFileService(string path)
    {
      fileWatch = new FileSystemWatcher(path);
      fileWatch.Changed += OnFileChanged;
    }

    private void OnFileChanged(object sender, FileSystemEventArgs e)
    {
      // blah blah
    }
  }

最接近解决此问题的MSDN 仅涵盖当IDisposable 的实例是短暂存在的用例,例如调用Dispose通过使用using:

仅当您使用非托管资源时才实施 IDisposable 直接地。如果您的应用程序仅使用实现 IDisposable,不提供 IDisposable 实现。相反,你 应该调用对象的 IDisposable.Dispose 实现,当你 用完了。

当然,在我们需要实例比方法调用更长时间的情况下,这是不可能的!?

我怀疑正确的方法是实现IDisposable(将责任传递给我的班级的创建者来处理它)但没有所有终结器和protected virtual void Dispose(bool disposing)逻辑,因为我没有任何未管理的资源,即:

  class FantasticFileService : IDisposable
  {
    private FileSystemWatcher fileWatch; // FileSystemWatcher is IDisposable

    public FantasticFileService(string watch)
    {
      fileWatch = new FileSystemWatcher(watch);
      fileWatch.Changed += OnFileChanged;
    }

    public void Dispose()
    {
      fileWatch.Dispose();
    }
  }

但是为什么任何官方文档都没有明确涵盖这个用例呢?而且它明确说如果你的类没有非托管资源就不要实现IDisposable,这让我犹豫不决......一个糟糕的程序员该怎么做?

【问题讨论】:

  • 您的第二个链接Implementing a Dispose Method 解释了他们说“在此处释放任何其他托管对象”。另外我不确定您是否正确实施了Dispose()。你不缺GC.SuppressFinalize(this);吗?
  • “我也不确定你是否正确地实现了 Dispose()”,很有可能!问题是 如何在这种特定场景下正确实施 dispose,我不会问我是否知道!
  • Could not find good link on "yes you should implement IDsiposable in this case",但我没有看到任何其他普遍同意的方式来指定您的对象最后需要显式清理。请注意,除非您的班级是 sealed (stackoverflow.com/questions/3882804/finalizer-and-idisposable),否则您仍然需要使用完整的 Dispose 模式

标签: c# .net


【解决方案1】:

看起来您的案例确实包含在某些文档中,即设计警告CA1001: Types that own disposable fields should be disposable

该链接有一个示例,说明您的 IDisposable 实现应该是什么样子。它将如下所示。最终的设计指南可以在CA1063: Implement IDisposable correctly找到。

  class FantasticFileService : IDisposable
  {
    private FileSystemWatcher fileWatch; // FileSystemWatcher is IDisposable

    public FantasticFileService(string watch)
    {
      fileWatch = new FileSystemWatcher(watch);
      fileWatch.Changed += OnFileChanged;
    }

    ~FantasticFileService()
    {
      Dispose(false);
    }

    protected virtual void Dispose(bool disposing)
    {
      if (disposing && fileWatch != null)
      {
        fileWatch.Dispose();
        fileWatch = null;
      }
    }

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

【讨论】:

  • 此外,在stackoverflow.com/questions/33508669/… 上看起来像一个类似的问题/答案
  • 谢谢我喜欢官方链接以及它明确谈论我的场景的事实。看起来很相似,但是我只是碰巧以 FileSystemWatcher 为例,它可以是任何 IDisposable
  • 缺少~FantasticFileService()
  • 虽然,为了后代,值得注意的是,添加析构函数根本不会改变代码的功能。另见 cmets@stackoverflow.com/a/628814/6137718
  • 确实链接页面说:“如果类不直接拥有任何非托管资源,它不应该实现终结器。”
【解决方案2】:

正如你所收集的,你还需要将FantasticFileService:IDisposable 设为一次性。 Dispose() 可用于摆脱托管资源以及非托管资源。

试试这样的:

class FantasticFileService:IDisposable
{
    private FileSystemWatcher fileWatch; // FileSystemWatcher is IDisposable
    private bool disposed;

    public FantasticFileService(string path)
    {
        fileWatch = new FileSystemWatcher(path);
        fileWatch.Changed += OnFileChanged;
    }

    private void OnFileChanged(object sender, FileSystemEventArgs e)
    {
        // blah blah
    }

    // Public implementation of Dispose pattern callable by consumers.
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    // Protected implementation of Dispose pattern.
    protected virtual void Dispose(bool disposing)
    {
        if (disposed)
            return;

        if (disposing)
        {
            if (fileWatch != null)
            {
                fileWatch.Dispose();
                fileWatch = null;                   
            }
            // Free any other managed objects here.
            //
        }

        // Free any unmanaged objects here.
        //
        disposed = true;
    }

    ~FantasticFileService()
    {
        Dispose(false);
    }
}

另见

【讨论】:

    猜你喜欢
    • 2012-03-28
    • 1970-01-01
    • 1970-01-01
    • 2012-05-05
    • 1970-01-01
    • 2012-03-17
    • 1970-01-01
    • 2013-09-29
    • 1970-01-01
    相关资源
    最近更新 更多