I skipped ahead a while back with my post on the exceptions theme, and it’s time to get back on track with stuff that would usually precede that rather involved topic during an FxCop backlog cleanup project.
The good news with the disposition and finalization topic is that its scope is quite a bit narrower than the exceptions topic. The bad news is that you’ll probably see almost as many preconceptions regarding how it works, particularly if you have quite a few developers who are accustomed to deterministic finalization. As with the exceptions topic, it’s probably a pretty good idea to start the topic from scratch, making the assumption that most of the developers on your team will get at least something from coverage of even the fundamentals of the subject matter.
Resources
This time around, Chris Brumme’s post on finalization is absolutely required reading, at least for the topic trainer. If you don’t understand at least 90% of that article, you probably don’t know enough about finalization to be teaching the topic.
You’ll also need some resources that are more on the “how to” side of things. The MSDN articles Implementing Finalize and Dispose to Clean Up Unmanaged Resources and Implementing a Dispose Method to provide a reasonable starting point around guidelines for finalization and disposition. By the time you complete your training on finalization and disposition, all the developers on your team should be able to read and understand these articles.
Some gotchas
By and large, the documentation available is pretty clear, and the recommended practices are relatively unambiguous. However, we did run into a few picky detail issues while tackling the disposition and finalization theme at FinRad:
- In a disposable class that contains a collection of disposable items, how does one deal with exceptions that might be thrown during the disposition of any individual item?
The issue here is that one wants to continue disposing of any remaining items even if an exception is thrown while disposing of any given item. However, one still wants to throw an exception out of the parent classDispose
method. The question here is exactly what should one end up throwing? One answer is to store any exceptions into some custom exception that contains an exception collection, then throw the resulting beastie at the end of the process. Unfortunately, there are several problems with this approach, not least of which is that the originalDispose
method caller isn’t likely to be want to iterate over the exception collection trying to decide what to do about each and every one of the member exceptions.
What we ended up deciding to do instead was to treat disposition of each individual collection item as if it we were disposing a field on the parent class. In other words, we wanted to expose the same exception scenario that would be seen if we were able to code the parentDispose
method like this:try
If one were able to do this, the only exception the caller of the parent class
{
this._someDisposableField.Dispose();
}
finally
{
try
{
this._someOtherDisposableField.Dispose();
}
finally
{
try
{
this._collectionOfDisposables[0].Dispose();
}
finally
{
try
{
this._collectionOfDisposables[1].Dispose();
}
finally
{
…
}
}
}
}Dispose
method would see is the last exception thrown in any of the individual try blocks. This is quite easy to simulate even while disposing in a loop. e.g.:try
Is this ideal? Obviously not, but I happen to believe that it presents less problems than any of the alternatives. If you think you have a better approach, I’d love to hear about it.
{
this._someDisposableField.Dispose();
}
finally
{
try
{
this._someOtherDisposableField.Dispose();
}
finally
{
try
{
Exception lastException = null;
foreach (IDisposable item in this._collectionOfDisposables)
{
try
{
item.Dispose();
}
catch (Exception ex)
{
lastException = ex;
}
}if (lastException != null) throw lastException;
}
finally
{
GC.SuppressFinalize(this);
}
}
} - What exactly is an unmanaged resource?
The basic rules for implementing disposition and finalization are the following:
- If a class has a disposable field, it should disposed from the
Dispose
method of the parent class. - If a class has a field that represents an unmanaged resource, this should be released from both the
Dispose
method and the finalizer of the parent class.
SqlConnection
should be disposed in the parent class finalizer? The simple answer is “no”. The barely more complicated answer is pretty much the only things you should be cleaning up during finalization areIntPtr
fields. If you’ve gone beyondIntPtr
to start usingSafeHandle
in .NET 2.0, you don’t even need worry about those since the unmanaged handle is already wrapped in a disposable, finalizable managed object. - If a class has a disposable field, it should disposed from the
- There’s no framework design guideline with respect to interface inheritance from IDisposable, but there probably ought to be.
Interfaces that are likely to be implemented by types that will need to be disposable should themselves be disposable. This is because you don’t want to end up having to write code that looks like this:IShouldBeDisposableButIsNot thingy = Factory.CreateThingammy();
Instead, you want to be able to simply write code like this:
try
{
//…
}
finally
{
IDisposable disposableThingy = thingy as IDisposable;
if (disposableThingy != null) disposableThingy.Dispose();
}using (IShouldBeDisposableAndIs thingy = Factory.CreateThingammy())
{
//…
}
The built-in rules
Here are the built-in rules that you’ll want to start activating during the disposition and finalization theme:
Category | Rule | In FxCop 1.35? | In VStudio 2005? |
---|---|---|---|
Design | ImplementIDisposableCorrectly | x | x |
TypesThatOwnDisposableFieldsShouldBeDisposable | x | x | |
TypesThatOwnNativeResourcesShouldBeDisposable | x | x | |
Performance | DisposeMethodsShouldCallSuppressFinalize | x | x |
RemoveEmptyFinalizers | x | ||
Reliability | DisposeObjectsBeforeLosingScope | x | |
Usage | DisposableFieldsShouldBeDisposed | x | x |
DisposableTypesShouldDeclareFinalizer | x | x | |
DisposeMethodsShouldCallBaseClassDispose | x | x | |
DoNotDisposeObjectsMultipleTimes | x | x | |
FinalizersShouldBeProtected | x | x | |
FinalizersShouldCallBaseClassFinalizer | x | x |
Some custom rule ideas
We haven’t created any custom rules yet around finalization and disposition at FinRad, but there are at least a couple that I would like to implement eventually:
- IDisposable.Dispose should be called from within a finally block (and the only other code in the finally block should be a cast to IDisposable)
- An interface with at least one disposable implementation should itself be disposable
That last one is bound to be interesting to try to author, but I’ve got loads of time to figure out how to implement it since there are quite a few more important rules to tackle first…
Thank you for the information. I have another “corner case” for your consideration : do you Dispose instances of MemoryStream ?
As everyone “knows” it holds no unmanaged resources…
Cheers,
–Jonathan
There are actually some pretty good reasons to explicitly dispose everything that is disposable, even if that disposition ultimately does very little. For example, if you’re coding against interfaces or base classes as much as possible, you’ll want to ensure that disposition is triggered all the time in order to cover the cases where it actually will have a significant effect (e.g.: if you happen to working with a FileStream rather than a MemoryStream).
Even if you’re not coding against interfaces or base classes, there is no guarantee that any given type’s disposition will continue to be quite as trivial in future releases. If you’re not disposing your memory streams now and the next version of the .NET Framework adds some significant resource releasing to MemoryStream.Dispose, you may end up with quite a bit of catch-up coding to do.
To be honest, I have to wonder why one would want to bother avoiding invoking disposition for the trivial cases. After all, if the Dispose method doesn’t happen to do much of anything, its performance cost will be tiny, so there doesn’t seem to be much point in going out of one’s way to avoid executing it.