Implementing IDisposable on a subclass when the parent also implements IDisposable
I have a parent and child class that both need to implement IDisposable
. Where should virtual
(and base.Dispose()
?) calls come into play? When I just override the Dispose(bool disposing)
call, it feels really strange stating that I implement IDisposable
without having an explicit Dispose()
function (just utilizing the inherited one), but having everything else.
What I had been doing (trivialized quite a bit):
internal class FooBase : IDisposable
{
Socket baseSocket;
private void SendNormalShutdown() { }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private bool _disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
SendNormalShutdown();
}
baseSocket.Close();
}
}
~FooBase()
{
Dispose(false);
}
}
internal class Foo : FooBase, IDisposable
{
Socket extraSocket;
private bool _disposed = false;
protected override void Dispose(bool disposing)
{
if (!_disposed)
{
extraSocket.Close();
}
base.Dispose(disposing);
}
~Foo()
{
Dispose(false);
}
}
When I just override the Dispose(bool disposing) call, it feels really strange stating that I implement IDisposable without having an explicit Dispose() function (just utilizing the inherited one), but having everything else.
This is something you shouldn't be concerned with.
When you subclass an IDisposable class, all of the "Dispose pattern" plumbing is already being handled for you by the base class. You really should do nothing but override the protected Dispose(bool)
method, and track whether you've been disposed already (to properly raise ObjectDisposedException
.)
For details, see my blog post on Subclassing from an IDisposable class.
Also, often, it's a good idea to consider encapsulating the IDisposable class instead of subclassing it. There are times when subclassing an IDisposable class is appropriate, but they are somewhat rare. Encapsulation is often a better alternative.
Why complicate things when you don't need to?
Since you don't encapsulate any unmanaged resources, you don't need all that mucking about with finalization. And, your classes are internal, which suggests that you control the inheritance hierarchy within your own assembly.
So, the straighforward approach would be:
internal class FooBase : IDisposable
{
Socket baseSocket;
private void SendNormalShutdown()
{
// ...
}
private bool _disposed = false;
public virtual void Dispose()
{
if (!_disposed)
{
SendNormalShutdown();
baseSocket.Close();
_disposed = true;
}
}
}
internal class Foo : FooBase
{
Socket extraSocket;
private bool _disposed = false;
public override void Dispose()
{
if (!_disposed)
{
extraSocket.Close();
_disposed = true;
}
base.Dispose();
}
}
Even when you do have unmanaged resources, I'd say you're much better off encapsulating them in their own disposable class and using them like you'd use any other disposable; as straighforward as the code above.
The idea of this pattern is that you override the virtual Dispose
method, calling base.Dispose
if necessary. The base class takes care of the rest, calling the virtual Dispose method (and hence the correct implementation). The subclass should not need to also implement IDisposable
(it is IDisposable
via inheritance)