Introduction
In GC 101, I discussed the reasons for Finalize
and Dispose
, and how to implement these methods in your components. The C# language has some nice built-in functionality to help you with the Disposing pattern, which I will discuss here.
Cool C# feature: using
Consider the following code:
SqlConnection cn = new SqlConnection(cnString);
cn.Open();
cn.Dispose();
If an exception had to be thrown on the call to Open
, Dispose
will never get called, and your resource might leak. I'm sure you already know the solution:
try
{
SqlConnection cn = new SqlConnection(cnString);
cn.Open();
}
finally
{
cn.Dispose();
}
This code does exactly what the first listing does, but is safer - you are guaranteed that Dispose
will be called. But, it is also much less readable! C# has a nice feature to help with readability here: the using
clause. Our code can be rewritten as:
using (SqlConnection cn = new SqlConnection(cnString))
{
cn.Open();
}
Lovely, isn�t it? As soon as the using
block exits, Dispose
will automatically be called on all objects that implement IDisposable
and are created with the using
-clause. If you look at the compiler-generated IL, you will see that a try
- finally
is actually implemented.
Cool C# feature: foreach
You might have collections of expensive (disposable) objects from time to time. To ease coding against your collection, have it implement IDisposable
:
internal class openDBConnectionsEnumerator : IEnumerator, IDisposable
{}
public class openDBConnections : IEnumerable
{
public IEnumerator GetEnumerator()
{
return new openDBConnectionsEnumerator();
}
}
Now, you can use your collection in a foreach
loop, and Dispose
is called automatically on your collection when the loop exits:
OpenDBConnections cons = new OpenDBConnections();
foreach(DBConnection in cons)
{
}
Performance issues
The GC has only one thread that calls Finalize
on all the objects in the finalization queue, and thus might have a tough time in keeping up with Finalizable objects created by more than one user thread. A shortened overview of a Finalizable object�s lifespan:

There are actions here that impacts negatively on performance:
- Enlisting in the Finalization queue
- Removing from Finalization queue to be enlisted in To Be Finalized queue
- Calling
Finalize
on the component
- Removing from To Be Finalized queue
It should be obvious that, if possible, the shortcut should be taken, and Finalizable components avoided. To do so, and this is quite important:
- Don�t create Finalizers (or destructors) for your components unless absolutely necessary.
- For components where you do need a destructor, always call
Dispose
on your component when appropriate. This suppresses the GC's call to Finalize
and saves you the overhead of calling Finalize
and enlisting in the To Be Finalized queue.
Threading
A component�s Dispose(bool)
method should never be called from both the GC�s finalizer thread and a user thread. There may be instances where more than one user thread calls the method. In this case, make your cleanup code thread safe in exactly the same way you�d make any code thread safe. If you are 100% sure that your code will not be called by more than one user thread at a time, don�t enforce thread-safety, as this impacts negatively on performance.
(You will also find this article on my blog).