#941 – Checking to See If Objects Are Disposable

If a type implements the IDisposable interface, you should always call the Dispose method on an instance of the class when you are done using it.  The presence of IDisposable indicates that the class has some resources that can be released prior to garbage collection.

Below is one pattern for checking to see if an object implements the IDisposable interface.

            Dog bob = new Dog("Bob", 5);
            bob.Bark();
            if (bob is IDisposable)
                ((IDisposable)bob).Dispose();

You can also use the using statement to automatically call Dispose on an object when you’re done using it.

Advertisement

#910 – One Example of a finally Block

You use a finally block when you have logic that should execute whether or not an exception occurs when executing a block of code.

One example of something that you might do in a finally block is to call a Dispose method on an object that implements IDisposable.  You would do this because you want to make sure that you always call Dispose on the disposable object, whether or not an exception occurs when using the object.

(Note: You can achieve the same pattern with the using statement, which automates invocation of a Dispose method).

            StreamWriter sw = new StreamWriter(@"D:\Log.txt");
            try
            {
                sw.Write(string.Format("Did something at {0}", DateTime.Now));
            }
            finally
            {
                sw.Dispose();
            }

#673 – Types Used in using Statement Must Implement IDisposable

The using statement is a shortcut for a try/finally block where the Dispose method is automatically called on any objects instantiated as part of the using statement.

            using (StreamWriter sw = new StreamWriter(@"D:\Hi.txt"))
            {
                sw.Write("Hi !");
            }
            // StreamWriter.Dispose automatically called

Because the Dispose method is called automatically on all objects instantiated as part of the using statement, each object must belong to a type that implements IDisposable.  The example below leads to a compile-time error because Dog does not implement IDisposable and therefore does not have a Dispose method.

            using (Dog d = new Dog("Kirby", 15))
            {
                d.Bark();
            }

#431 – The using Statement Automates Invocation of the Dispose Method

A class may implement the IDisposable interface, providing a Dispose method, to allow for deterministic destruction.  Client code calls Dispose when it is done using the object, telling it to release resources that it might be holding.

It can be hard to ensure that you always call Dispose when appropriate, especially when exceptions occur.

The using statement in C# specifies the scope in which you want to use an object and guarantees that the Dispose method will be called when the object goes out of scope.

            using (StreamWriter writer =
                new StreamWriter(@"D:\Remember.txt"))
            {
                writer.Write("RIP Steve Jobs, 1955-2011");
            }

If we look at the IL generated for the using statement, we can see that it is converted to a try/finally block and the Dispose method of the StreamWriter object is called in the finally block.

#430 – A Dispose Pattern Example

If you want to control when an object’s unmanaged resources are released, you can follow the dispose pattern, implementing a Dispose method.

Here’s a complete example.  We create a method to release resources that is called either when a client invokes Dispose directly or when the CLR is finalizing the object.

    public class Dog : IDisposable
    {
        // Prevent dispose from happening more than once
        private bool disposed = false;

        // IDisposable.Dispose
        public void Dispose()
        {
            // Explicitly dispose of resources
            DoDispose(true);

            // Tell GC not to finalize us--we've already done it manually
            GC.SuppressFinalize(this);
        }

        // Function called via Dispose method or via Finalizer
        protected virtual void DoDispose(bool explicitDispose)
        {
            if (!disposed)
            {
                // Free some resources only when invoking via Dispose
                if (explicitDispose)
                    FreeManagedResources();   // Define this method

                // Free unmanaged resources here--whether via Dispose
                //   or via finalizer
                FreeUnmanagedResources();

                disposed = true;
            }
        }

        // Finalizer
        ~Dog()
        {
            DoDispose(false);
        }
    }

#429 – Use the Dispose Pattern for Deterministic Destruction

You can implement a finalizer in a class to explicitly release unmanaged resources before an object’s memory is freed.  Drawbacks of this approach include:

  • You don’t control when the object’s resources are cleaned up
  • A finalizer can’t make use of any other managed objects  (they may have already been finalized)

Another pattern for releasing unmanaged resources is for a class to implement the IDisposable interface by providing a Dispose method.  Dispose is meant to clean up the object’s resources when it’s called.  A client of the class can decide exactly when it wants to release the object’s resources (deterministic destruction).  Benefits of this pattern include:

  • Can release resources earlier, not waiting for finalization
  • Dispose logic can make use of other managed resources
    public class Dog : IDisposable
    {
        public void Dispose()
        {
            // Release unmanaged resources here

            // Note: need logic to prevent double disposal, etc.
        }