Friday, March 23, 2012

Implementing IDisposable Interface-Part I

In previous posts we discussed ICmparer and IComparable interfaces, today we will discuss another important interface called IDisposable. Before we dive into its implementation, lets refresh our memory on how things were before .NET framework.

Before .NET Framework, if you initialized an object such as opening a database connection, you must manually dispose it. You could eventually bring your system to its knees, if you forgot to dispose your objects.

Framework solved this problem by introducing the concept of Garbage Collector. GC runs on a background thread and uses complex mechanism to determine which initialized objects are no longer being used and can be safely destroyed. It then disposes those objects for you. There is only one caveat - it can only dispose the managed objects i.e. the objects that are part of the .NET Framework library. If you invoke a non managed resource such as an IntPtr to acquire a Windows Handle or some other unmanaged resource (via PInvoke), you are on your own and must dispose them.

Framework provides an IDisposable interface with a Dispose method that you can implement in classes which will initialize and consume unmanaged resources.

Let's see an example.

In this example, we will obtain the handle associated with current process and assign it to a variable of type IntPtr which is unmanaged and must be disposed manually. We will implement Dispose method and then dispose this object.

Unmanaged Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace IDisposableInterface
{
    class Unmanaged:IDisposable
    
    {
        private bool _disposed;
        private IntPtr _handle;

        //initializer method 
        public Unmanaged()
    {
        //we create a new pointer and associate it with the current process
        // This is unmanaged code and _handle must be disposed explicity 
        //and GC will not collect it
         _handle = new IntPtr();
        _handle = System.Diagnostics.Process.GetCurrentProcess().Handle;
    }
        public IntPtr Handle
        {
            get { return _handle; }
        }
      //notice we have declared this method as private because this is not thread-safe 
      //and should only be called once. Here we are declaring a global variable _declared 
        //to ensure it only executes once.
       private void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                //release unmanaged resources
                 _handle = IntPtr.Zero;
                _disposed = true;
            }
        }
        public void Dispose()
        {
            Dispose(true);
        }

    }
}


Dispose method is not thread-safe and in a multi-threaded application you must use synclock before calling this method. Also, you cannot dispose an object once it is disposed, so care must be taken to dispose it only once. In above class, we have declared a private Dispose method to ensure we only dispose an object once.

Calling the Dispose Method
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IDisposableInterface
{
    class Program
    {
        static void Main(string[] args)
        {
            // instantiate unmanaged class and retrieve the handle
            Unmanaged notManaged = new Unmanaged();
            Console.WriteLine("Handle:={0}", notManaged.Handle);
            //Dispose
            notManaged.Dispose();
            Console.Read();
        }
    }
}


Since this is unmanaged code, GC will not dispose it so there are no worries, but if you were using managed code and had implemented your own dispose method, you will have to ensure GC doesn't try to dispose the object that you have already disposed.

We will see how to properly implement your own dispose method for managed code and what may be the advantages of doing so in the next post.

Thank you.



No comments:

Post a Comment