After reading the answer here, I decided to mark my class as sealed in order to simplify the IDisposable implementation. Why does sealed affect the implementation of IDispo
If a class which implements IDisposable is not sealed, it is likely that a derived class will need to do something in response to Dispose, but the base-class actions for Dispose should be performed as well. If the class exposes a public Dispose member which will always be synonymous with IDisposable.Dispose, the necessary semantics could be achieved in C# by simply using implicit interface implementation with a public virtual Dispose method.
There are two problems with that approach:
Note that Microsoft seems to have intended its Dispose pattern to be used in the cases where a base class does not override Finalize, but a derived class uses Finalize for cleanup. While that may have been the intent, it is not a good pattern for that purpose. With very few exceptions, the only classes which should only override Finalize for cleanup are those which derive from trivial classes like Object. If a class implements IDisposable but does not override Finalize, the only purpose for which a derived class should override Finalize is to sound an alarm if Finalize ever gets called, and even that usage is debatable (a better pattern would be:
class whatever:IDisposable
{
IDisposable DisposedStatusObject;
// Generate a static dummy object instance we can use as a sentinel value
// It needs to be `IDisposable`, but shouldn't actually hold any resources.
static IDisposable DisposedStatusDisposed = new List().GetEnumerator();
public bool Disposed {get {return (DisposedStatusObject == DisposedStatusDisposed);} }
whatever()
{
DisposedStatusObject = new DisposalAlarm(); // First thing in constructor
}
void Dispose()
{
IDisposable prevStatus;
prevStatus = Interlocked.Exchange(DisposedStatus, DisposedStatusDisposed);
if (prevStatus != DisposedStatusDisposed)
{
Dispose(true);
prevStatus.Dispose();
}
}
}
The DisposalAlarm() class is assumed to be a class with an overridden Finalize() method which sounds an alarm if that Finalize() method gets called without its Dispose() method being called first. The Dispose method for whatever will ensure that, if the derived-class method returns properly, the alarm will get cancelled. Note that if an instance of whatever has an unsuppressed finalizer, everything to which whatever holds a direct or indirect reference will have to be kept around until that finalizer has either run or been suppressed. By contrast, the addition of a DisposalAlarm object does not extend the lifetime of anything in whatever.