Using IDisposable correctly - finalizers

by Dominic Zukiewicz 20. March 2008 11:36
It sounds easy, implement IDisposable, call Dispose() when you've finished with it, no problem right?

Well, even with the advice of the "using" statement, you still can't guarantee that the developer may still forget to do this! So we need to guarantee that they are tidied up!

The answer is finalizers, or known to many C++ developers as destructors. Finalizers are a last chance to tidy up any resources when the GC is finally releasing the resources. You do not need to manually clean up managed resources as these are released by the garbage collector anyway, so we need to ensure the unmanaged resources are ALWAYS tidied up.

There are 3 steps to this:
  1. Implement IDisposable and create a Dispose method.
  2. Create a new Dispose method taking a bool parameter to flag whether to clean up managed resources.
  3. Add a finalizer to call method (2).

So here are the 3 steps in action:

Implement IDisposable

public class MyClass : IDisposable 
{ 
   SqlConnection _connection = new SqlConnection(); 
 
   //Implementation here 
   
   public void Dispose() 
   { 
      //Implementation here 
   } 
}


Create a private implementation of Dispose(bool), telling it whether to dispose of managed resources. Managed resources are always disposed of. Notice that a call to GC.SuppressFinalize() is made, to tell them GC that the object doesn't need finalizing. This may seem like an overhead, but it merely sets a bit field on the object, so there is little if no overhead with this action.
public class MyClass : IDisposable 
{ 
   SqlConnection _connection = new SqlConnection(); 
 
   //Implementation here 
   
   public void Dispose() 
   { 
      Dispose(true); 
      System.GC.SuppressFinalize(this); //Don't trigger finalizer 
   } 
 
   private void Dispose(bool isDisposing) 
   {
      try 
      { 
         //Clean up unmanaged 
 
         //CLean uo managed
         if (isDisposing) 
         { 
            _connection.Dispose(); 
         }
      }
      finally 
      {
         _connection = null; 
      } 
   }
}


Last, but not least, is to tell the finalizer to dispose of all unmanaged resources only. Again, this is because the garbage collector will release any managed resources anyway.

public class MyClass : IDisposable 
{ 
   SqlConnection _connection = new SqlConnection(); 
 
   //Implementation here
 
   public void Dispose() 
   {
      Dispose(true); 
      System.GC.SuppressFinalize(this); 
   } 
 
   private void Dispose(bool isDisposing) 
   { 
      try 
      { 
         //Clean up unmanaged 
 
         //Clean up the managed resources, when necessary 
         if (isDisposing) 
         { 
            _connection.Dispose(); 
         }
      }
      finally 
      {
         _connection = null; 
      } 
   } 
 
   ~MyClass() 
   { 
      Dispose(false); 
   } 
}

A final point, notice the if logic, which disposes of managed resources when it is called from Dispose() and not from the finalizer?

The reason is that when calling Dispose(), you really do want to release those resources immediately. If you wait for the finalizer to do this, it could be a long long time before it is released. You may think it still is calling the Dispose(bool) method unnecessarily, but how will unmanaged resources by tidied if they haven't called Dispose() ??

Tags:

Powered by BlogEngine.NET 1.5.0.7
Theme by Interakting

Interakting

A full service digital agency offering online strategy, design and usability, systems integration and online marketing services that deliver real business benefits and ensure your online objectives are met.

Calendar

<<  July 2010  >>
MoTuWeThFrSaSu
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

View posts in large calendar