This week, I’m passing along a tip I ran across several months back when trying to track down some resources that weren’t being released as I expected. Normally, you can let .NET’s garbage collection take care of cleaning up after your objects, unless you are using unmanaged resources such as a database connection. The .NET framework provides the IDisposable interface for just such a case.
Even when your class does implement IDisposable, there is no guarantee that the Dispose() method will be called, so you should always place a call to Dispose() in your object’s finalizer (destructor). This is needed because of how garbage collection works. When the garbage collector runs, any objects without finalizers are simply deleted from memory, providing the potential for resource leakage. Any objects with a finalizer are left in memory and their finalizer is executed. This is where you have the opportunity to safely release any resources your object uses. So, take a look at how you implement IDisposable.
public class GoodResourceCitizen : IDisposable { private bool _IsDisposed = false; ~GoodResourceCitizen() { Dispose(false); } public void Dispose() { Dispose(true); // Tell the garbage collector not to call the finalizer // since all the cleanup will already be done. GC.SuppressFinalize(true); } protected virtual void Dispose(bool IsDisposing) { if (_IsDisposed) return; if (IsDisposing) { // Free any managed resources in this section } // Free any unmanaged resources in this section _IsDisposed = true; } }
The overloaded virtual version of Dispose() allows derived classes to easily call the base class to properly release resources. The finalizer simply calls the overloaded Dispose() method. The regular Dispose() method calls the overloaded version and then tells the garbage collector that there is no need to call the finalizer for this object. You do need to be careful of what code you put in the Dispose() method. The only thing you should do in Dispose() is clean up and free resources. You should not be calling other methods or referencing any other objects. You do not know in what order objects are disposed, so you may be attempting to access a dead object. Worse yet, you could resurrect the object, but because it has already be disposed once, the garbage collector will ignore it.
Implementing IDisposable is a good practice to get into, especially for any classes that use unmanaged resources. Although the .NET garbage collector does a good job of cleaning up resources, you have the responsibility to do whatever you can to aid it by making your objects good resource citizens. You also will end up with more stable and maintainable classes.
About the Author
Jay Miller is a Software Engineer with Electronic Tracking Systems, a company dedicated to robbery prevention, apprehension, and recovery based in Carrollton, Texas. Jay has been working with .NET since the release of the first beta and is co-author of Learn Microsoft Visual Basic.Net In a Weekend. Jay can be reached via email at jmiller@sm-ets.com.