Reputation: 131
I see that the common guideline to implement the disposable pattern in C# is to have an abstract base class that implements the Dispose() method from IDisposable interface and provides a protected virtual Disposable(bool) method. Then sub-classes need to override Disposable(bool) and always do something like:
if (!disposed && disposing)
{
// dispose resources here
disposed = true;
}
My question is: wouldn't be possible to reuse this pattern? I don't like to have to manage this "disposed state" in every subclass. We could have some abstract base class like this:
public abstract class AbstractResource : IDisposable
{
private bool myDisposed = false;
protected abstract void ReleaseUnmanagedResources();
protected virtual void ReleaseManagedResources()
{
// optionally override this to explicitly call Dispose() of other IDisposable objects
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!myDisposed)
{
if (disposing)
{
ReleaseManagedResources();
}
ReleaseUnmanagedResources();
myDisposed = true;
}
}
~AbstractResource()
{
Dispose(false);
}
}
Then users of this class only need to implement ReleaseUnmanagedResources and (optionally) ReleaseManagedResources. No need to deal with booleans.
I've found that this article proposes a similar technique. But that is it! Nobody else mentions it. Are there flaws with this approach?
Upvotes: 2
Views: 446
Reputation: 415800
It's worse than you think. If you have a class heirarchy like this, you probably need to check disposed
in every method and property, since the class object can live long past the lifetime of the unmanaged resource, to be sure you never access a disposed resource. This means your abstract class is really not very much help.
It's not as bad as you think. You probably should not be implementing either the finalizer (~AbstractResource()
) or the complete Dispose pattern in the first place.
It's common to believe classes need these that in fact should not have them at all. Just because you use an unmanaged resource in a class, it does not necessarily mean that class needs IDisposable
, if you use the resource in a way where it is disposed by it's own type. Just because you implement IDisposable
does not mean you need a finalizer, if the resource controlled by IDisposable
is already finalized by another type.
This article is also worth your time:
IDisposable: What Your Mother Never Told You About Resource Deallocation
Upvotes: 3
Reputation: 77304
The biggest flaw with this method is that it takes away a finite resource... the ability to derive from exactly one class means if I use your implementation, I basically can kiss OOP goodbye because I will need to derive many classes from your class and cannot derive them from another class as I could if I implemented the interface.
So in the real world, you'd have a wild mix of some classes using your baseclass, some rolling their own baseclass for business purposes that already incorporates IDisposable
and some just implementing the interface. I cannot speak for everybody, but I'd rather have the same construct applied to all classes using a tool (R# for example) than having a wild mixture of things.
If we had the ability to derive from more than one base class, it might be a thing, but we don't in C#.
Upvotes: 4