Implementing the IDisposable interface can be a good idea, if done correctly! It allows you to clean up a lot of try… finally code and replace it with the fancy “using” blocks, because the “using” block implicitly invokes the dispose method and only works on types that implement IDisposable….

Lets say I define a type… (with a very poor name!)

1 public class Disposable : IDisposable
2   {
3     public void Dispose( )
4     {
5       throw new NotImplementedException( );
6     }
7   }

I could use the type like this…

1 public void Using( )
2   {
3     using ( Disposable myType = new Disposable( ) ) {
4       Console.WriteLine( myType );
5     }
6   }

Which is actually doing something like this…

 1 public void TryFinally( )
 2   {
 3     IDisposable myType = null;
 4     try {
 5       myType = new Disposable( );
 6       Console.WriteLine( myType );
 7     }
 8     finally {
 9       if ( myType != null ) {
10         myType.Dispose( );
11       }
12     }
13   }

The proper implementation of the Dispose pattern looks like this block of code…

 1 public class Disposable : IDisposable {
 2     public Disposable( IDbConnection connection ) {
 3       _connection = connection;
 4     }
 5 
 6     public void Dispose( ) {
 7       Dispose( true );
 8       GC.SuppressFinalize( this );
 9     }
10 
11     protected virtual void Dispose( Boolean disposing ) {
12       if ( disposing ) {
13         if ( _connection != null ) {
14           _connection.Close( );
15         }
16       }
17     }
18 
19     private IDbConnection _connection;
20   }

So why do we need a protected virtual method named Dispose that takes in a boolean paramater, when the IDisposable interface only demands a method with a signature of public void Dispose()?

The boolean paramter tells if the method was invoked from the finalizer (aka destructor, which can be called at some unknown point in time by the garbage collector, which may be well after the resource has already been cleaned up by it’s finalizer) or from client code explicitly calling the IDisposable.Dispose method. If the method is called from the finalizer, then disposing is false and it’s not safe to touch any resources or other objects. (You don’t want to raise exceptions in your finalizer!)

This makes sure that any resources used by your type does not get touched within the finalizer, since you can’t tell if that resource has already been finalized by it’s finalizer!

Since it’s expected that your dispose will be cleaning up any resources used by your time, there is no sense in allowing your type to be finalized AGAIN! By calling GC.SuppressFinalize, you’re telling the garbage collector not to finalize this type, because it has already been cleaned up. This should only be called if no exceptions are raised from your cleanup! (Which is why SuppressFinalize, should be called after the call to Dispose( true ) and not before!

For more information check out…

Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries (Microsoft .NET Development Series) by Krzysztof Cwalina, Brad Abrams

Read more… msdn msdn msdn

comments powered by Disqus