Monday, 12 March 2012

Implementing IDisposable Properly

I just found out that I haven't been disposing correctly. Here's my newest IDisposable implementation:

        //Stores whether everything has been disposed or not. It's possible
        //to call .Dispose() on an object and then try to use it again. With
        //this field, you can check before trying to access a resource.
        //Default is false (as per all booleans)
        private bool _disposed;
 
        //This is a C# finalizer, called when the garbage collector is going
        //to clean up an object. This is kind of expensive, but we need to
        //make sure we are disposing of objects. Having a finalizer makes
        //sure we dispose of our resources even if we forget to call .Dispose().
        //Finalizers force the garbage collector to keep track of who has them
        //and makes the garbage collector require two passes to erase an
        //object: one pass to call the finalizer, one pass to release memory
        ~SampleClass()
        {
            //Calls a private method we have made, telling it to only release
            //unmanaged resources. Managed resources will have been cleared out
            //already, since the CLR keeps a reference count.
            Dispose(false);
        }
 
        //Implementation of the IDisposable interface
        public void Dispose()
        {
            //Calls our private method, letting it know that we need to let
            //go of both managed and unmanaged resources
            Dispose(true);
            //Tells the garbage collector that we don't need to run the
            //finalizer for this class, since we are going to clean up
            //ourselves. This prevents the costly running of the finalizer
            GC.SuppressFinalize(this);
        }
 
        //A private method just for us. The parameter determines whether
        //we clean up only unmanaged resources, or if we also include
        //managed resources
        private void Dispose(bool disposing)
        {
            //Checks if the disposals have been done already
            if (_disposed)
            {
                //No disposal done? OK. Fair enough. Are we disposing of
                //only managed resources?
                if (disposing)
                {
                    //We take care of only managed resources in this block
 
                    //If the resource is still around, dispose of it.
                    if(_managedResource != null)_managedResource.Dispose();
                }
                //Unmanaged resources need to be cleaned up for sure, so
                //let's do that here. Call the code to clean up the
                //resources here. In this case, let's pretend we have a
                //COM object to be cleaned up.
                Marshal.ReleaseComObject(_unmanagedResource);
 
                //We set everything to null to remove this object's
                //references for certain.
                _unmanagedResource = null;
                _managedResource = null;
 
                //Set the disposed flag to true to let the rest of the class
                //know.
                _disposed = true;
            }
        }
Once we implement IDisposable like this, we are guaranteed to have our objects cleaned up properly no matter how our code is being used, which is the goal of even using IDisposable :)

Any tips to improve this code? Leave a comment!

1 comment: