0

我有一个拥有托管一次性资源(.NET PerformanceCounter)的基类。我了解在类上实现 IDisposable 以便我可以在资源上显式调用 Dispose。从我看到的示例中,人们通常使用私有布尔成员变量“disposed”并将其在 Dispose 内部设置为 true。稍后,如果尝试访问公共方法或属性,如果“disposed”为真,则会引发 ObjectDisposedException。

在子类中呢?子类如何在其公共方法和属性中知道它们已被释放?起初我认为子类不需要任何特殊的东西(比如实现他们自己的 Dispose 版本),因为需要处理的东西只在基类中(假设子类不会添加任何数据需要显式处理)并且基类的 Dispose 应该处理它。子类是否应该仅仅为了设置自己的“已处理”成员变量而重写基类的虚拟 Dispose 方法?

这是所讨论的类层次结构的一个非常精简的版本。

class BaseCounter : IBaseCounter, IDisposable
{
  protected System.Diagnostics.PerformanceCounter pc;
  private bool disposed;
  public BaseCounter(string name)
  {
    disposed = false;
    pc = CreatePerformanceCounter(name);
  }

  #region IBaseCounter
  public string Name
  {
    get 
    {
      if (disposed) throw new ObjectDisposedException("object has been disposed");
      return pc.CounterName;
    }
  }
  public string InstanceName
  {
    get
    {
      if (disposed) throw new ObjectDisposedException("object has been disposed");
      return pc.InstanceName;
    }
  }
  #endregion IBaseCounter

  #region IDisposable
  protected virtual void Dispose(bool disposing)
  {
    if (!disposed)
    {
      if (disposing)
      {
        if (pc != null)
        {
          pc.Dispose();
        }
        pc = null;
        disposed = true;
      }
    }
  }

  public void Dispose()
  {
    Dispose(true);
  }
  #endregion IDisposable
}

class ReadableCounter : BaseCounter, IReadableCounter //my own interface
{
  public ReadableCounter(string name)
    : base(name)
  {
  }

  #region IReadableCounter 
  public Int64 CounterValue()
  {
    return pc.RawValue;
  }
  #endregion IReadableCounter
}

class WritableCounter : BaseCounter, IWritableCounter
{
  public WritableCounter(string name)
    : base(name)
  {
  }

  #region IWritableCounter 
  public Increment()
  {
    pc.Increment();
  }
  #endregion IWritableCounter
}

在我们的系统中,ReadableCounter 和 WritableCounter 是 BaseCounter 的唯一子类,它们只是通过代码生成过程再被子类化到一个级别。附加的子类级别只添加了一个特定的名称,以便可以创建直接对应于命名计数器的对象(例如,如果有一个计数器用于计算生成的小部件的数量,它最终被封装在一个 WidgetCounter 类中. WidgetCounter 包含允许创建“WidgetCounter”性能计数器的知识(实际上,只是作为字符串的计数器名称)。

只有代码生成的类被开发人员直接使用,所以我们会有这样的东西:

class WritableWidgetCounter : WritableCounter
{
  public WritableWidgetCounter
    : base ("WidgetCounter")
  {
  }
}

class ReadableWidgetCounter : ReadableCounter
{
   public ReadableWidgetCounter
     : base ("WidgetCounter")
   {
   }
}

因此,您会看到基类拥有并管理 PerformanceCounter 对象(它是一次性的),而子类使用 PerformanceCounter。

如果我有这样的代码:

IWritableCounter wc = new WritableWidgetCounter();
wc.Increment();
wc.Dispose();
wc.Increment();
wc = null;

WritableCounter 如何以增量方式知道它已被处置?ReadableCoutner 和 WritableCounter 是否应该简单地覆盖 BaseCounter 的

protected virtual void Dispose(bool disposing)

像这样的东西:

protected virtual void Dispose(bool disposing)
{
  disposed = true; //Nothing to dispose, simply remember being disposed
  base.Dispose(disposing); //delegate to base
}

只是设置一个 ReadableCounter/WritableCounter 级别的“disposed”成员变量?

如果基类(BaseCounter)声明为受保护(或使其成为受保护的属性)呢?这样,子类可以引用它,而不是仅仅为了记住 Dispose 已经发生而添加 Dispose 方法。

我错过了这艘船吗?

4

2 回答 2

0

我见过一些具有公共 IsDisposed 属性的一次性类。你可以这样做并在你的子类中检查它。

我做的另一件事是一个通用的受保护的“验证”方法,所有子类方法都调用(并且可以覆盖)。如果它返回,一切都很好,否则它可能会抛出。这将使您的子类与一次性内脏完全隔离。

于 2009-06-19T19:29:27.173 回答
0

我在基类和子类中都有用于实现 IDisposable 的片段。你可能想要一个子类。

我想我从 MSDN 刷了大部分代码。

这是基类 IDisposable 的代码(不是您想要的):

#region IDisposable Members
// Track whether Dispose has been called.
private bool _disposed = false;

// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
    Dispose(true);
    // Take yourself off the Finalization queue 
    // to prevent finalization code for this object
    // from executing a second time.
    GC.SuppressFinalize(this);
}

// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the 
// runtime from inside the finalizer and you should not reference 
// other objects. Only unmanaged resources can be disposed.
protected virtual void Dispose(bool disposing)
{
    // Check to see if Dispose has already been called.
    if (!this._disposed)
    {
        // If disposing equals true, dispose all managed 
        // and unmanaged resources.
        if (disposing)
        {
            // TODO: Dispose managed resources.

        }
        // Release unmanaged resources. If disposing is false, 
        // only the following code is executed.
        // TODO: Release unmanaged resources

        // Note that this is not thread safe.
        // Another thread could start disposing the object
        // after the managed resources are disposed,
        // but before the disposed flag is set to true.
        // If thread safety is necessary, it must be
        // implemented by the client.
    }
    _disposed = true;
}

// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method 
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~Program()
{
    // Do not re-create Dispose clean-up code here.
    // Calling Dispose(false) is optimal in terms of
    // readability and maintainability.
    Dispose(false);
}
#endregion

这是我在子类中使用的代码(这是您想要的代码):

#region IDisposable Members
// Track whether Dispose has been called.
private bool _disposed = false;

// Design pattern for a derived class.
// Note that this derived class inherently implements the 
// IDisposable interface because it is implemented in the base class.
// This derived class does not have a Finalize method
// or a Dispose method without parameters because it inherits 
// them from the base class.
protected override void Dispose(bool disposing)
{
    if (!this.disposed)
    {
        try
        {
            if (disposing)
            {
                // Release the managed resources you added in
                // this derived class here.
                // TODO: Dispose managed resources.
            }
            // Release the native unmanaged resources you added
            // in this derived class here.
            // TODO: Release unmanaged resources.
            _disposed = true;
        }
        finally
        {
            // Call Dispose on your base class.
            base.Dispose(disposing);
        }
    }
}
#endregion

寻找TODO:标记。

于 2009-06-19T21:42:45.967 回答