BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

.NET Framework
.NET 1.1+

Implementing IDisposable

Classes that use unmanaged resources, or that hold references to managed objects that themselves use unmanaged resources, should always implement the IDisposable interface. The correct use of this interface ensures the efficient release of resources.

Using the Interface

With the class now correctly implementing the IDisposable pattern you can free up its resources on demand. The following code, added to the Main method, shows how. Note that the third line of code causes an exception as we are trying to access a member after the object was disposed.

SimpleDisposableResource sdr = new SimpleDisposableResource();
sdr.Dispose();
Console.WriteLine(sdr.FileLength());    // ObjectDisposedException

Implementing IDisposable with a Finalizer

If your class uses unmanaged resources directly, these should be released within the Dispose method. As we have seen, the method can be called directly by the user. Where unmanaged resources are present we must ensure that they can also be released by the garbage collector. This is achieved by adding a finalizer and having the finalizer call the Dispose method with a parameter of "false". The false value indicates that the method was not called manually.

The following code shows the entire implementation for a class that uses an IntPtr structure, which holds a handle requiring manual release. The sample also includes a Stream object to show the differences between the release of the managed and unmanaged resources. Note the addition of the finalizer, named ~DisposableWithFinalizer and that the handle is released whether the method is called automatically or manually.

class DisposableWithFinalizer : IDisposable
{
    Stream _stream;
    IntPtr _handle;
    private bool _disposed;

    public DisposableWithFinalizer()
    {
        _stream = File.OpenRead(@"c:\test\test.txt");
        _handle = new IntPtr();
    }

    public long FileLength()
    {
        if (_disposed) throw new ObjectDisposedException("MyObject");
        return _stream.Length;
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                // Dispose managed resources
                if (_stream != null) _stream.Dispose();
            }

            // Dispose unmanaged resources
            _handle = IntPtr.Zero;

            _stream = null;
            _disposed = true;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    ~DisposableWithFinalizer()
    {
        Dispose(false);
    }
}

Implementing IDisposable in an Inheritance Hierarchy

When creating an inheritance hierarchy where a base class implements IDisposable, you do not need to implement the interface in the subclasses. If you did, this would lead to unnecessary calls to the Dispose method, creating a performance penalty. Instead, if the subclass uses unmanaged resources, override the parameterised Dispose method and use this to clean up your resources. To ensure that the base class is also released correctly, the method should call its base equivalent.

The following example contains a class that is derived from the simple code shown earlier

class DisposableSubclass : SimpleDisposableResource
{
    Stream _stream;

    public DisposableSubclass()
    {
        _stream = File.OpenRead(@"c:\test\test.txt");
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _stream.Dispose();
        }

        _stream = null;

        base.Dispose(disposing);
    }
}

Further Notes

This pattern for disposing of resources described is not thread-safe. In most situations this is not an issue. However, when thread safety is required, you should implement a lock around the dispose operations and in any members that utilise the resources.

Whenever you use a class that implements IDisposable, you should call Dispose when you no longer need its objects. This ensures that its resources are freed up at the earliest time possible. You should never assume that an object that uses unmanaged resources will be disposed automatically, as it is possible that the garbage collector will never call the finalizer.

6 August 2008