Last week someone asked me whether the use of destructors in C++ was similar to the try … catch … finally block within C#, since C++ doesn’t have the notion of a finally block. I hadn’t thought about this before. A few days later I noticed that Herb Sutter wrote a post stating that:
The C++ destructor model is exactly the same as the [Java] Dispose and [C#] using patterns, except that it is far easier to use and a direct language feature and correct by default, instead of a coding pattern that is off by default and causing correctness or performance problems when it is forgotten
Basically Herb likes the C++ model better because it doesn’t depend on developers having to remember to use ‘using statements’ or call the Dispose method when making use of the code.
The issue is that there’s a lot involved when dealing with IDisposable in .NET. While the using statement in C# makes it easier to ensure correctness there's still work to do on the implementation side. As Sean Schade mentions, many developers (mistakenly) think that the garbage collector will automatically call dispose. Unfortunately this won’t happen unless you write code in your Finalizer that calls the Dispose method. The MSDN documentation on the Dispose Pattern has all of the steps that need to be considered when writing code that implements or uses IDisposable. It’s worth a look as this is an important topic to understand in .NET development.
At the same time as all of this there’s been a great thread on the Windows OT mailing list about the IDispose pattern in ADO.NET highlighting many of these issues.
I also read somewhere that there should be some VS Add-in/FxCop rule that can highlight when a Type that implements IDispose has been used without being wrapped in a using statement or being called explicitly. I think this is a great idea in the situations where it works. The problem, as Brad Wilson highlights in an OT post, is that it if you use interface-based programming it isn’t always possible to know whether a reference to an interface actually implements IDisposable, without inspecting the concrete Type at runtime, as his sample code demonstrates:
void Foo(IDbConnection conn)
{
using (IDbCommand cmd = conn.CreateCommand())
{
[...]
}
}