Use IDisposable to Release .NET Resources
The Dispose pattern properly releases resources but imposes overhead.
by Mickey Williams
VSLive! Orlando, September 18, 2002
Note: Mickey Williams is presenting "Apply IHttpHandler and IHttpModule" at ASP Live! Orlando, Wednesday, September 18.
You use the Dispose pattern to properly release non-memory resources such as database connections, Win32 interop components, and operating system handles. You can't rely on garbage collection to free these resources quickly, because garbage collection is triggered by memory pressure in the managed heap. You can quickly consume scarce resources such as database connections, adversely affecting the scalability of your application. However, you should not implement the Dispose pattern when it isn't required, because it imposes overhead that you can avoid in most cases.
The Dispose pattern is formalized in .NET through the IDisposable interface, which includes a single method, Dispose:
interface IDisposable
{
void Dispose();
}
The most clear-cut case where a class should implement IDisposable is when instances of the class will have strong ownership over an unmanaged resource, such as a native database connection or operating system handle.
In addition, note a frequently overlooked case where you should implement IDisposable. When a class implements IDisposable, proper use of its instances requires the Dispose method to be called when the object is no longer needed. When you implement a class that owns other classes that implement IDisposable, therefore, you must ensure that Dispose is invoked. This usually means that you must implement IDisposable in that class, even though it might not deal with unmanaged resources directly.
Here's the typical pattern for implementing IDisposable properly:
public class SlalomRacer: IDisposable
{
bool _disposed = false;
public bool IsDisposed
{
get { return _disposed; }
set { _disposed = value; }
}
~SlalomRacer()
{
InternalDispose(false);
}
public void Dispose()
{
InternalDispose(true);
}
protected void InternalDispose(bool disposing)
{
if(disposing)
{
GC.SuppressFinalize(this);
_managedThing.Dispose();
}
_unmanagedThing.Dispose();
}
[...]
}
When IDisposable is implemented as shown in the preceding code fragment, you can invoke the disposal code in two ways. First, if you invoke the Dispose method directly, managed and unmanaged objects are disposed. Note that finalization is suppressed as an optimization step. Also note that it's possible to call Dispose multiple times safely. After Dispose is invoked, a flag is set to ensure that any attempt to use methods will run afoul of code like this:
public void SeekHotTub()
{
if(IsDisposed)
throw new ObjectDisposedException("BT");
}
The ObjectDisposedException notifies the caller that a previously disposed object has been used. Raising an exception when invoking a method on a disposed object is a perfectly reasonable diagnostic strategyafter all, you shouldn't be using disposed objects.
Second, if you don't invoke the Dispose method, the finalizer will call Dispose(false), which takes a slightly different code path from the previous case. First, no managed objects should be touched, even if they implement IDisposable. You can't assume that the object references are validthese objects might be waiting for finalization, or might have already been finalized. There's also no need to call GC.SuppressFinalization, because the objects are already being finalized.
Finally, if you're using C#, you should take advantage of the language's built-in support for IDisposable through the using statement:
using(SlalomRacer mickey = new SlalomRacer())
{
// use mickey here
mickey.RunGates();
mickey.GetStitches();
}
// mickey disposed automatically here
The C# compiler will emit IL code that calls Dispose properly, even if exceptions occur.
About the Author
Mickey Williams is the author of Microsoft Visual C# .NET, from Microsoft Press. He is also the founder of CodeV Technologies, a provider of tools and components for Windows developers. Active with object-oriented development since the 1980s, he has written many books about Windows programming tools and frequently speaks at conferences in the United States and Europe. An expert in Microsoft .NET development technologies, Mickey is an instructor for .NET Experts, where he teaches courses on the .NET Framework, XML, and SOAP.
|