Saturday, October 16, 2010

IDisposable and the Using statement

 

.Net has been around for about a decade now and I still run across code fairly regularly that completely skips out on closing connections or disposing of unmanaged resources.  Here is a basic overview that covers 95+% of when to implement IDisposable and when to wrap something in a using statement.

You'll occasionally run across objects that have a method called Dispose()

show_in_intellisense

The Dispose method exists to ensure that unmanaged resources are released.  It should only be used when you're using parts of the .Net framework that use unmanaged code (all database connections, GDI+, and most file related tasks).  The benefit of the method is that it gives you a guaranteed way to make sure that connections are closed.

When creating a class that owns unmanaged resources you can ensure that their dispose methods are called by implementing IDisposable on your own class:

class MyDisposableClass : IDisposable
    {
        private SqlConnection sqlConn;
        private SqlCommand sqlCmd; 
 
        public MyDisposableClass()
        {
            this.sqlConn = new SqlConnection();
            this.sqlConn.Open();
            this.sqlCmd.Connection = new SqlConnection();
        } 
 
        public void Dispose()
        {
            sqlConn.Dispose();
            sqlCmd.Dispose();
        }
    } 

To make things easier .Net added the using keyword.  Using allows you to create code blocks which call Dispose() automagically when their scope ends.

static void Main(string[] args)
{
using (var DisposableClass = new MyDisposableClass())
{
// Do stuff that needs DisposableClass here
}
}

This is functionally equivalent to doing the following Try/Finally code:

static void Main(string[] args)
{
   var DisposableClass = new MyDisposableClass())
    try
   {
       //Do stuff here
   }
   finally
   {
       DisposableClass.Dispose();
   }
} 

You can of course chain using's together when using unmanaged objects like this:

static void Main(string[] args)
{
    using (var sqlConnection = new SqlConnection())
    {
        using (var sqlCommand = new SqlCommand())
        {
            sqlConnection.Open();
            sqlCommand.Connection = sqlConnection;
        } // sqlCommand.Dispose() is called here
    } // sqlConnection.Dispose() is called here
}

References:


http://msdn.microsoft.com/en-us/library/yh598w02.aspx
http://msdn.microsoft.com/en-us/library/aa664736(VS.71).aspx
http://www.codeproject.com/KB/cs/tinguusingstatement.aspx  (most in depth)