IDisposable: The contentious Dispose pattern

on Ben’s Blog

Yucky stuff

I convinced myself that I needed to take some action with the IDisposable interface, so I started to do some research on best practices. The first place I looked was the MSDN documentation, where I found the "official" pattern:

[sourcecode language="csharp"] public class Base: IDisposable { private bool disposed = false;

//Implement IDisposable. public void Dispose() { Dispose(true); GC.SuppressFinalize(this); }

protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { // Free other state (managed objects). } // Free your own state (unmanaged objects). // Set large fields to null. disposed = true; } }

// Use C# destructor syntax for finalization code. ~Base() { // Simply call Dispose(false). Dispose (false); } } [/sourcecode]

The first thing I noticed was that it doesn't look very elegant. This surprised me because, in general, the .NET framework is very elegant and well-crafted. What's this business with calling GC.SuppressFinalize, the disposing flag, and the scary C# finalizer with C++ destructor syntax? (I will hereon refer to them as "yucky stuff.") There must be a better way, or there's something I'm not understanding here. And I didn't want to go blindly apply this pattern everywhere before understanding it some more. This prompted more digging.

What Your Mother Never Told You About Resource Deallocation

Stephen Cleary wrote an excellent article that covers the problems with IDisposable and also proposes some of his own best practices that simplify the pattern significantly. I highly recommend reading the entire article. He validates my reaction that IDisposable objects are cumbersome to use, and that the Microsoft-endorsed pattern is needlessly complex.

The main issue is that the pattern is designed for the general case that handles both explicit and implicit resource cleanup. But I believe most .NET developers are normally concerned only with explicit cleanup, and so most of the yucky stuff becomes extraneous.

As I learned, if you design your classes properly, you can simplify the pattern significantly:

[sourcecode language="csharp"] public sealed class BetterWay : IDisposable { Font coolFont; public BetterWay() { coolFont = new Font("Comic Sans", 12); }

public void Dispose() { coolFont.Dispose(); } } [/sourcecode]

What happened to all the yucky stuffs? Stephen Cleary's "Disposable Design Principle" makes them go away:

Level 0 types only deal with unmanaged resources. Level 1 types only deal with managed resources, and thus, implementing IDisposable for Level 1 types is simple. Since most .NET developers live in Level 1-land, they can use this pattern and be happier. Regarding this implementation, Stephen Cleary notes:

He also covers this implementation, which he calls "The Second Rule Of Implementing IDisposable" on his blog. (Implementing IDisposable for Level 0 types is harder; you should read the rest of the article and refer to "The Third Rule of Implementing IDisposable.")

Feeling good about it

Stephen Cleary's best practices were looking more attractive, but I needed more evidence to feel comfortable about deviating from the Microsoft-sanctioned way. As I searched more, I found others who supported my desire to use a different pattern. This Stack Overflow answer and follow-up comments debate this very topic. Jon Skeet, as usual, does a good job of explaining the issue, and states that "if you seal your classes, it makes life a lot easier: the pattern of overriding Dispose to call a new virtual Dispose(bool) method etc is only relevant when your class is designed for inheritance." I found another post that was similar in spirit. And even a proposal for changing C#, prompted by the difficulty of the official pattern.

Now that I understand things a lot better, I'll be using this new pattern when designing my classes. Less yucky stuff.