Tuesday, February 7, 2012

Implement IDisposible in .NET

The pattern for disposing an object, referred to as a dispose pattern, imposes order on the lifetime of an object. The dispose pattern is used only for objects that access unmanaged resources. This is because the garbage collector is very efficient at reclaiming unused managed objects.
A type's Disposemethod should release all the resources that it owns. It should also release all resources owned by its base types by calling its parent type's Dispose method. The parent type's Dispose method should release all resources that it owns and in turn call its parent type's Dispose method, propagating this pattern through the hierarchy of base types. To help ensure that resources are always cleaned up appropriately, a Dispose method should be callable multiple times without throwing an exception.
There is no performance benefit in implementing the Dispose method on types that use only managed resources (such as arrays) because they are automatically reclaimed by the garbage collector. Use the Dispose method primarily on managed objects that use native resources and on COM objects that are exposed to the .NET Framework. Managed objects that use native resources (such as the FileStream class) implement the IDisposable interface.


A Dispose method should call the SuppressFinalize method for the object it is disposing. If the object is currently on the finalization queue, SuppressFinalize prevents its Finalize method from being called. Remember that executing a Finalize method is costly to performance. If your Dispose method has already done the work to clean up the object, then it is not necessary for the garbage collector to call the object's Finalize method.
The code example provided for the GC.KeepAlive method shows how aggressive garbage collection can cause a finalizer to run while a member of the reclaimed object is still executing. It is a good idea to call the KeepAlive method at the end of a lengthy Dispose method.


The recommended IDisposable pattern is here. When programming a class that uses IDisposable, generally you should use two patterns:
When implementing a sealed class that doesn't use unmanaged resources, you simply implement a Dispose method as with normal interface implementations:
public sealed class A : IDisposable
{
    public void Dispose()
    {
        // get rid of managed resources, call Dispose on member variables...
    }
}
When implementing an unsealed class, or one using unmanaged resources, do it like this:
public class B : IDisposable
{    
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // get rid of managed resources
        }   
        // get rid of unmanaged resources
    }

    ~B()
    {
        Dispose(false);
    }
}
Doing it this way means that if the user of your class forgets to call Dispose(), the unmanaged resources are still got rid of when the finalizer is called. It also gives inheritors of your class an easy way of dealing with unmanaged resources themselves, if you've already implemented IDisposable.
The call to GC.SuppressFinalize in the Dispose() method means the finalizer isn't called, as it isn't needed once all the resources are disposed of using the explicit call to Dispose(). This also saves resources, as extra computing effort is needed in the CLR to keep track of classes with active finalizers.
When a class implements the IDisposable interface, it means that somewhere there are some unmanaged resources that should be got rid of when you've finished using the class. The actual resources are encapsulated within the classes; you don't need to explicitly delete them. Simply calling Dispose() or wrapping the class in a using(...) {} will make sure any unmanaged resources are got rid of as necessary.

Calling dispose in implementation:
 public partial class DisposeTest : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            MyTestClass obj = new MyTestClass();
            try {
                obj.Test();
               
            }
            catch (Exception ex) { throw; }
            finally { obj.Dispose(); }
           
        }
    }

    public class MyTestClass : IDisposable
    {
        DataSet ds = new DataSet();
        public void Test()
        {
            HttpContext.Current.Response.Write("This is test");
       
        }
       public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                // free managed resources
                if (ds != null)
                {
                    ds.Dispose();                  
                }           
              
            }
          
            // Free your own state (unmanaged objects).
            // Set large fields to null.
            ds = null;
          
        }

        ~MyTestClass()
        {
            // Simply call Dispose(false).
            Dispose(false);
        }
    }

Reference:
http://msdn.microsoft.com/en-us/library/b1yfkh5e%28v=vs.80%29.aspxhttp://msdn.microsoft.com/en-us/library/b1yfkh5e%28v=vs.80%29.aspx
http://msdn.microsoft.com/en-us/library/fs2xkftw.aspx

No comments:

Post a Comment