Beating the Disposal Blues

Author John Hatton | 18.01.2008 | Category Developers

This blog is largely a note to my future self, as I know I’ll be here again, and hopefully will google for the right terms to find this entry.

I had just added our standard code to ensure that a control was disposed of properly:

~DetailList()
{
if (!this._disposed)
{
throw new InvalidOperationException("Disposed not explicitly called on " GetType().FullName ".");
}
}

Using Resharper’s Unit Test Runner, all my tests passed. I checked it in, and fired up the build machine. The build uses NUNIT console to run its tests; they all passed there, too, but the build failed because this code was throwing this InvalidOperationException all over!

Notice, the key problem here is that this exception is thrown on the finalization thread, at indeterminate times. So ReSharper might not notice it at all, and no test runner really knows which test caused it. Even with Nunit, the message was listed under the wrong test method a couple of times; this is quite understandable; suddenly this exception comes through, how’s the test runner supposed to know that the fault was actually 8 tests back? If you have a thousand or so unit tests, it can be tough to figure out which one forgot to dispose of the object.

I got out of this mess by storing the stack trace, at the time of construction, with the object:

public DetailList()
{
#if DEBUG
_stackAtConstruction = new StackTrace();
#endif

Then, in the finalizer,  I just cough that back up:

~DetailList()
{
if (!this._disposed)
{
string trace = "Was not recorded.";
if (_stackAtConstruction != null)
{
trace = _stackAtConstruction.ToString();
}
throw new InvalidOperationException("Disposed not explicitly called on " GetType().FullName ". Stack at creation was " trace);
}
}

 

 

The 4 Cycle Solution

Discount

zp8497586rq