I have a base class that owns a managed disposable resource (.NET PerformanceCounter). I understand about implementing IDisposable on the class so that I can explicitly call Dispose on the resource. From the examples I have seen, people typically use a private boolean member variable "disposed" and set it to true inside of Dispose. Later, if there is an attempt to access a public method or property, an ObjectDisposedException is raised if "disposed" is true.
What about in the subclasses? How would the subclasses, in their public methods and properties, know that that they had been disposed? At first I thought that the subclasses would not have to anything special (like implement their own version of Dispose) since the thing that needs to be disposed is only in the base class (let's assume that the subclasses won't be adding any data that needs to be explicitly disposed) and the base class' Dispose should handle that. Should the subclasses override the base class' virtual Dispose method solely for the purpose of setting its own "disposed" member variable?
Here is a very stripped-down version of the class hierarchy in question.
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
}
In our system, ReadableCounter and WritableCounter are the only subclasses of BaseCounter and they are only subclassed to one more level via a code generation processes. The additional subclassing level only addes a specific name so that it becomes possible to create objects that correspond directly to named counters (e.g. if there is a counter that is used to count the number of widgets produced, it ends up being encapsulated in a WidgetCounter class. WidgetCounter contains the knowledge (really, just the counter name as a string) to allow the "WidgetCounter" performance counter to be created.
Only the code-generated classes are used directly by developers, so we would have something like this:
class WritableWidgetCounter : WritableCounter
{
public WritableWidgetCounter
: base ("WidgetCounter")
{
}
}
class ReadableWidgetCounter : ReadableCounter
{
public ReadableWidgetCounter
: base ("WidgetCounter")
{
}
}
So, you see that the base class owns and manages the PerformanceCounter object (which is disposable) while the subclasses use the PerformanceCounter.
If I have code like this:
IWritableCounter wc = new WritableWidgetCounter();
wc.Increment();
wc.Dispose();
wc.Increment();
wc = null;
How could WritableCounter know, in Increment, that it had been disposed? Should ReadableCoutner and WritableCounter simply override the BaseCounter's
protected virtual void Dispose(bool disposing)
something like this:
protected virtual void Dispose(bool disposing)
{
disposed = true; //Nothing to dispose, simply remember being disposed
base.Dispose(disposing); //delegate to base
}
simply to set a ReadableCounter/WritableCounter-level "disposed" member variable?
How about if the base class (BaseCounter) declared disposed as protected (or made it a protected property)? That way, the subclasses could refer to it rather than adding a Dispose method simply for the purpose of remembering that Dispose had happened.
Am I missing the boat on this?