AJ’s blog

May 28, 2007

IDisposable – 1, 2, 3, …

Filed under: .NET, .NET Framework, C#, Software Development — ajdotnet @ 4:28 pm

Note: See also the sequel IDisposable Reloaded

recycleIDisposable is one of these beasts. Considered to be common knowledge and yet I regularly encounter code that simply ignores the demand. A well documented pattern and yet I occasionally stumble over improper usage of the pattern. And this is just the beginning; the finer details are lost more often than not.

Calling IDisposable

IDisposable’s sole purpose is to free scarce or expensive resources quickly and cleanly. The usually mentioned examples are files, database connections, and unmanaged resources. Rarely mentioned is the fact that a class becomes an expensive resource by the very fact that it implements IDisposable (and asuming the pattern below is used, including the finalizer. If Dispose() is not called the object will survive one garbage collection, making it to the second generation and live longer than intended, blocking memory and requiring a more thorough GC to get freed.)

Therefore the advice is: If it implements IDisposable, call it. Always!

Basic implementation

Implementing IDisposable is a well documented pattern but it regularly is not observed properly. The gist is:

  1. Implement IDisposable.Dispose() to call a protected virtual method Dispose(bool disposing) with true and deregister the object from finalization (i.e. call GC.SuppressFinalize(this);)
  2. Implement the finalizer to call Dispose(false) as fallback, should the caller forget the call to IDisposable.
  3. Implement Dispose(bool) to free managed resources if disposing is true and to always free unmanaged resources.

public class DisposableObject: IDisposable
{
    ~DisposableObject()
    {
        Dispose(false);
    }
    
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // free managed resources
        }
        
        // free unmanaged resources
    }
}

If you implement IDisposable you have to follow this pattern. Period. And you do implement it if your class manages other resources, e.g. if it holds a file reference or some kind of unmanaged handle.

OK, up to here we’ve covered what I should hope to be common knowledge. But there is more. Not terribly complicated but things to consider anyway.

Advanced patterns

One decision to be made is how the object will behave after disposing it.

  1. It could be revived, e.g. a file could be reopened. In this case it should GC.ReRegisterForFinalize(); to start all over.
  2. The call could be oblivious, i.e. not care at all but also not providing the means to do anything with it (e.g. providing the necessary calls only as c’tors).
  3. It could be unforgiving; in which case it would throw an ObjectDisposedException.

Please note that the following classes build on the above example (i.e. DisposableObject).

Revivable object:

public class RevivableObject : DisposableObject
{
    public RevivableObject()
    {
        // not yet…
        GC.SuppressFinalize(this);
    }
    
    public void Open(/*…*/)
    {
        // open the resource
        
        // and make sure the GC knows about this
        GC.ReRegisterForFinalize(this);
    }
}

Oblivious object: 

public class UseOnlyOnceObject : DisposableObject
{
    public UseOnlyOnceObject(/*…*/)
    {
        // open the resource only via c’tor
    }
    
}

Guarded object: Every method needs to call AssertNotDisposed() as precondition.

public class GuardedObject : DisposableObject
{
    bool _disposed = false;
    
    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        _disposed = true;
    }
    
    protected void AssertNotDisposed()
    {
        if (_disposed)
            throw new ObjectDisposedException(GetType().FullName);
    }
    
    void Foo()
    {
        // check preconditions
        AssertNotDisposed();
        
        // …
    }
}

Dispose and tell

A fair number of classes do not only dispose themselves, they also tell about it — via a respective event (e.g. the component class.)

public class ObservableObject : DisposableObject
{
    public event EventHandler Disposed;
    
    protected virtual void OnDisposed(EventArgs ea)
    {
        if (Disposed != null)
            Disposed(this, ea);
    }
    
    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        OnDisposed(EventArgs.Empty);
    }
}

Object graphs

Consider the following use case: You implement some kind of controller pattern for your web pages; the controller manages references to business services. A simple implementation would look like this:

public interface IBusinessService
{
}

public class Controller
{
    Dictionary<string, IBusinessService> _services= new Dictionary<string,IBusinessService>();
    
    public IBusinessService GetBusinessService(string name)
    {
        IBusinessService ret= null;
        _services.TryGetValue(name, out ret);
        if (ret == null)
        {
            ret = CreateBusinessService(name);
            _services[name] = ret;
        }
        return ret;
    }
    
    protected virtual IBusinessService CreateBusinessService(string name)
    {
        // create business service, e.g. using a factory
        return null;
    }
}

public class PageWithController: Page
{
    Controller _controller;
    
    public Controller Controller
    {
        get { return _controller; }
    }
    
    protected override void OnPreInit(EventArgs e)
    {
        _controller = CreateController();
        base.OnPreInit(e);
    }
    
    protected virtual Controller CreateController()
    {
        // create controller , e.g. using a factory
        return new Controller();
    }
    
}

Now, what does that have to do with IDisposable? No disposable object is taking part in this sample, right?
However this implementation lays the infrastructure to be used with derived classes, controllers as well as business services. And those derived classes may very well implement IDisposable, e.g. a business service holding a database reference. Should the implementor of that business service have to build the disposing infrastructure for that service? Or should the infrastructure anticipate that need and already be aware of IDisposable? Take that as rhetorical question and have a look at the corrections:

public class Controller: GuardedObject
{
    // code as above…
    
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            DisposeHelper.DisposeElements(_services.Values);
            _services = null;
        }
        base.Dispose(disposing);
    }
    
}

public class PageWithController: Page
{
    // code as above…
    
    public override void Dispose()
    {
        DisposeHelper.Dispose(_controller);
        _controller = null;
        base.Dispose();
    }
}

I leave the implementation of the DisposeHelper class to your imagination.

So, the advice in this case is: If you for lay some kind of basic infrastructure, anticipate the usage of disposable objects and build an uninterrupted “dispose trail”.

That’s all for now folks,
AJ.NET

kick it on DotNetKicks.com

Blog at WordPress.com.