拥有托管可支配资源的IDisposable基类,在子类中做什么?

时间:2009-06-18 22:30:02

标签: idisposable performancecounter

我有一个拥有托管可支配资源(.NET PerformanceCounter)的基类。我理解在类上实现IDisposable,以便我可以在资源上显式调用Dispose。从我看到的例子中,人们通常使用私有布尔成员变量“dispos”并在Dispose内部将其设置为true。稍后,如果尝试访问公共方法或属性,则如果“dispos”为true,则引发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怎么能在Increment中知道它已被处理掉了? 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级“处置”成员变量?

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

我错过了这艘船吗?

2 个答案:

答案 0 :(得分:0)

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

我做的另一件事是所有子类方法调用(并且可以覆盖)的通用保护'Validate'方法。如果它返回,一切都很好,否则它可能会抛出。这样可以完全隔离你的子类和一次性内脏。

答案 1 :(得分: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:标记。