我有一个拥有托管可支配资源(.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方法。
我错过了这艘船吗?
答案 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:
标记。