3/03/2007

IDisposable and Conservative Politics

There is a saying "You become a Conservative when you've got something to conserve".

In the programming world, it could be said that "You should only implement IDisposable when you've got something to Dispose". Here is an interesting Q/A interchange between a confused C# newsgroup poster, with some very good answers by Barry Kelly:


Q: "A discussion arose recently in a code review about whether or not one should implement IDisposible (and then call it) on an object which has neither unmanaged resources nor managed resources which are resource intensive (db connections, filestreams, etc.)."

A: If a class implements IDisposable, that tells me as a programmer that I *need* to call Dispose() when appropriate. If the class doesn't own other objects which implement IDisposable, and isn't likely to do so, then I would say - don't implement it.

But if you do implement it, implement it properly. Create a protected virtual void Dispose(bool disposing) method, and have your Dispose() implementation call Dispose(true). Then put all your logic in the protected virtual method. That way, descendants can extend the class properly.

Q: "It seems to me that if you do not have such items to explicitly dispose yourself, then it is best to let the Garbage Collector do its work when it determines it is the best time to clean up these objects."

A: Calling Dispose on an object whose class implements IDisposable does not cause it to be collected ahead of time. Dispose() is just a method call, like any other, a programming convention. There's no magic in the CLR relating to Dispose, the only magic is in C# and its 'using' construct - which is essentially a type-dependent macro.

Q: "But, my question is, does it matter? If I have SimpleObject, and I call simpleObject.Dispose() when I'm done with it, is there an associated performance liability over not calling the method?"

A: Possibly, it will cost more, because you're pointlessly calling a method. But the cost will be vanishingly small.

Q: Also, if I write an empty Dispose() method :
Is this object removed from the managed heap when I call that method?

A: No. Explicit deallocation is asymptotically more expensive than a copying / compacting GC like .NET's. That is, it would be more expensive if it did remove it.

Q: "Or is it actually cleaned up on Finalization, because it does not"


A: Only objects which implement finalizers are subject to finalization. And objects should only implement finalizers if they need finalization, that is, if they explicitly wrap an unmanaged resource. Typically this means they have a field of type IntPtr, or they descend from CriticalFinalizerObject, they call unmanaged methods via P/Invoke, etc.



If you aren't familiar, the Dispose pattern is defined by the IDisposable interface.

For classes that aren't sealed and need to do resource cleanup, you should follow the Dispose pattern, which has been designed to ensure reliable, predictable cleanup, to prevent temporary resource leaks, and to provide a standard, unambiguous pattern for disposable classes. It also aids derived classes to correctly release base class resources:


protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// Dispose managed resources.
}

// If there are unmanaged resources to release,
// they need to be released here.
}
disposed = true;

// If it is available, make the call to the
// base class's Dispose(Boolean) method
base.Dispose(disposing);
}


Again, the bottom line: If your class doesn't have resources that it needs to dispose, you do not need to implement IDisposable. This will be the predominant case, so quit worrying about Dispose and go write some good code!