Monday, August 9, 2010

Everything what you might want to know about the Disposable pattern

Thought thrives on conflict. Today I had a discussion with my technical leader who ashamed me that I don't know how to implement IDisposable correctly. It turned out it was true as I really lacked in knowledge of the Disposable pattern. On the other hand my implementation was actually almost right even with my knowledge:)

So what we've got?

public class CustomWriter : IDisposable
{
    private readonly Stream _stream;

    public CustomWriter(Stream stream)
    {
        Helper.CheckNull("stream", stream);
        _stream = stream;
    }

    // some methods that deal with _stream
}

My first implementation of Dispose method was the simplest that can be only:)

public void Dispose()
{
    _stream.Dispose(); 
}

Is this code good?:) I think every experience .NET developer knows the right answer but question can be tricky for some junior developers.

Let's get deep into the problem.

The Disposable pattern. You can find it in MSDN, it is shown in example for the IDisposable interface. You should remember that you must throw ObjectDisposedException in the beginning of every method if object is disposed already. So in general the skeleton of the class implemented IDisposable can be like following:

public class DisposableClass : IDisposable
{
    // the boolean flag whether the current object is disposed or not
    private bool _disposed;

    // check if the current object is disposed
    private void CheckDisposed()
    {
        if (_disposed)
        {
            throw new ObjectDisposedException(GetType().FullName);
        }
    }

    public void SomeMethod()
    {
        // check if not disposed
        CheckDisposed();

        // some logic here
    }

    public void Dispose()
    {
        // dispose all managed and unmanaged resources
        Dispose(true);

        // suppress calling of the object destructor
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposeManagedResources)
    {
        if (!_disposed)
        {
            if (disposeManagedResources)
            {
                // dispose managed resources here
            }
            // dispose unmanaged resources here
              
            // turn on the 'disposed' flag
            _disposed = true;
        }
    }

    ~DisposableClass()
    {
        // only unmanaged resources disposed here
        Dispose(false);
    }
}

Pattern is pretty straightforward. If the user of the class wants to release resources explicitly than he can call Dispose method which does all work. Also you should suppress calling of the destructor by the garbage collector as it is no need in this already.

The main point here that you should not try to release managed resources in destructor because they are in undefined state actually by this moment - the garbage collector might release some or all unmanaged resources already.

How differs the code above from example code from MSDN?
  1. The CheckDisposed method is created which should be called in the beginning of each other method.
  2. The argument of the parametrized Dispose method is renamed to disposeManagedResources. As for me the variable name disposing is not self-explanatory.
  3. The Dispose method made protected virtual. In this way you can redefine it in derived classes for actual needs.
The simplified pattern. What happens if our class will not have the unmanaged resources? Fine, the destructor will do nothing - kill it! GC.SuppressFinalize(this) is not needed anymore as we don't have the destructor - kill it! disposeManagedResources will be always true - kill it! Why we should have another Dispose method without parameter? Kill it too!:) So what we've got now:

public class DisposableClass : IDisposable
{
    // the boolean flag whether the current object is disposed or not
    private bool _disposed;

    // check if the current object is disposed
    public void CheckDisposed()
    {
        if (_disposed)
        {
            throw new ObjectDisposedException(GetType().FullName);
        }
    }

    public void SomeMethod()
    {
        // check if not disposed
        CheckDisposed();

        // some logic here
    }

    public void Dispose()
    {
        if (!_disposed)
        {
            // dispose managed resources here

            _disposed = true;
        }
    }
}

Notice the important moment. When we are talking about unmanaged resources we mean those resources which we should release on our own as the garbage collector cannot deal with them. Feel the difference - even if the Stream object operates internally with some unmanaged resources we don't care about it. From our side the Stream object is the managed resource and it is enough to call its Dispose method to be sure that all is done there.

So was my code so wrong in the beginning of this post?:) Apparently no. The only issue there that I could call _stream.Dispose() more than once. Actually it shouldn't be the problem (actually _stream.Dispose() will do nothing in further calls) but it is not good anyway. Adding the _disposed field and checking it is all what I needed to add.

Happy disposing for you!:)

5 comments:

  1. Nice writing buddy and Many thanks.
    You have cleared many confusions I had after reading a dozen of articles.

    But I need a real life example code. I know I sound dumb. But I'm very new to C#.

    ReplyDelete
  2. Sorry for late response. What kind of real life example do you need?

    I think I could make new post with some examples if you give me some ideas.

    ReplyDelete
  3. This is a very nice article clearly explaining the importance of each line of code in the dispose pattern .

    ReplyDelete
  4. I'm confused about this last example. Why do you need to worry about the Disposal pattern if your class does not manage unmanaged resources? Or put another way, if your class only manages managed resources, you don't have to worry about disposing them, right?

    ReplyDelete
  5.  You can manage managed resources which in their turn may or may not to manage unmanaged resources. For example, if you have underlined Stream instance, it could be the instance of MemoryStream or FileStream but you'll never know.
    Does it make sense?

    ReplyDelete