【问题标题】:Is Dispose(bool) method necessary if a finalizer isn't implemented?如果未实现终结器,是否需要 Dispose(bool) 方法?
【发布时间】:2016-08-03 10:12:33
【问题描述】:

虽然 Internet 和 SOF 上广泛讨论了 Dispose Pattern,但我找不到任何资源可以回答我的问题。

因此,请在将其标记为重复之前阅读到最后。如果你能指出我之前错过的一个问题,我会很乐意删除这个问题。


我见过很多类(盲目地?)在没有实现终结器的情况下实现了 dispose 模式。

MSDN article on Dispose Pattern 说:

布尔参数 disposing 指示该方法是从 IDisposable.Dispose 实现还是从终结器调用的。 Dispose(bool) 实现应该在访问其他引用对象(例如,前面示例中的资源字段)之前检查参数。只有在从 IDisposable.Dispose 实现调用方法时(当 disposing 参数等于 true 时)才能访问此类对象。 如果方法是从终结器调用的(disposing 为 false),则不应访问其他对象。原因是对象以不可预测的顺序完成,因此它们或它们的任何依赖项可能已经完成。

据我了解,GC 调用终结器方法(如果已实现),该方法又应调用参数为 false 的 Dispose(bool) 方法。

我的第一个问题是,如果一个类没有实现终结器,那么 Dispose(bool) 是否会被调用,参数为 false? (例如,我没有遇到过的 CLR 中的某些内容)

我了解 Dispose(bool) 可用于确保对象仅被释放一次。

因此,我的第二个问题是,如果一个类不需要实现终结器,那么它可以像下面这样简单地实现 Dispose 方法吗?

private bool objectDisposed;
public void Dispose()
{
    if (!objectDisposed)
    {
        // Release/dispose managed resources
        // ...
        // ...

        objectDisposed = true;
    }
}

【问题讨论】:

  • This extensive article on Dispose 将回答您的所有问题(编辑:链接到回退版本,因为格式正确)
  • 谢谢大家,我已经阅读了第一篇。
  • 简单的答案是“不!”然而,如果一个基类实现并且您的派生类也有一些东西要处理,那么该模式的病毒功能可能会发挥作用,那么您除了重写 Dispose(bool) 方法之外什么也做不了。
  • 他们当然可以。问题开始了,因为 Dispose() 通常不在 Base 类中声明为虚拟的。因此,如果客户端代码将派生类对象存储在基类引用中并调用 Dispose(),那么只有基类的 Dispose() 方法会执行。处置模式要求 Dispose(bool) 是虚拟的。

标签: c# .net memory-leaks garbage-collection dispose


【解决方案1】:

我的第一个问题是,如果一个类没有实现终结器,那么 Dispose(bool) 是否曾经被调用,参数为假? (例如。 通过 CLR 中我没有遇到过的东西)

没有

因此,我的第二个问题是一个类是否不需要实现 那么终结器是否可以简单地实现 Dispose 方法,例如 下面?

我不会,但你可以。如果这样做,如果要扩展此类,您将重新发明 IDisposable 模式。正如 HansPassant 在评论中指出的那样,如果有派生类,IDisposable 模式会非常方便。我宁愿一开始就遵循这种模式。

基类

using System;

class BaseClass : IDisposable
{
   // Flag: Has Dispose already been called?
   bool disposed = false;

   // 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) {
         // Free any other managed objects here.
         //
      }

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

   // Only if there are unmanaged resources.
   ~BaseClass()
   {
      Dispose(false);
   }
}

派生类

using System;

class DerivedClass : BaseClass
{
   // Flag: Has Dispose already been called?
   bool disposed = false;

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

      if (disposing) {
         // Free any other managed objects here.
         //
      }

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

      // Call the base class implementation.
      base.Dispose(disposing);
   }

   // Only if there are unmanaged resources.
   ~DerivedClass()
   {
      Dispose(false);
   }
}

【讨论】:

  • 要么这样做,要么使类密封,使其无法扩展。
  • 我们真的必须摆脱这种废话处理模式,这个答案对我们没有帮助。新规则:如果您不密封类,则总是 将 Dispose() 方法设为虚拟。顺便说一句,C++ 中的标准规则。
猜你喜欢
  • 2016-04-04
  • 1970-01-01
  • 1970-01-01
  • 2016-06-25
  • 2013-01-22
  • 2012-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多