You should follow the conventional pattern for implementing Dispose
. Making Dispose()
virtual is considered bad practice, because the conventional pattern emphasizes reuse of code in "managed cleanup" (API client calling Dispose()
directly or via using
) and "unmanaged cleanup" (GC calling finalizer). To remind, the pattern is this:
public class Base
{
~Base()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this); // so that Dispose(false) isn't called later
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// Dispose all owned managed objects
}
// Release unmanaged resources
}
}
Key here is that there's no duplication between finalizer and Dispose
for unmanaged cleanup, and yet any derived class can extend both managed and unmanaged cleanup.
For your case, what you should do is this:
protected abstract void Dispose(bool disposing)
and leave everything else as is. Even that is of dubious value, since you're enforcing your derived classes to implement Dispose
now - and how do you know that all of them need it? If your base class has nothing to dispose, but most derived classes likely do (with a few exceptions, perhaps), then just provide an empty implementation. It is what System.IO.Stream
(itself abstract) does, so there is precedent.