Exception Safety and IDisposable Factories

C# is mostly relieved from the stress of exception safety, thanks to garbage collections. But in some cases it must be handled. A common case is factories creating more than one IDisposable object.

Coming from a C++ background, the notion of exception safety is natural to me. For a C++ developer exception safety is as important as… as… ehhmm… I can’t really find any equivalent in C#. I guess that’s good because exception safety is a pain to deal with. The most common reason to care about exception safety in C++ is memory management and in C# that is a non issue thanks to the garbage collector. For other resources C# offers the using construct and in 95% of the cases it deals with the messy details of ensuring that the resource is disposed even in the event of an exception.

Unfortunately there are those 5% that isn’t handled by the using statement. In this post I’ll use a constructor that allocates a precious resource in the form of objects implementing IDisposable. The principle is the same however for any function that creates a IDisposable object whose lifetime will exceed the function execution.

The Problem

Let’s get to some code. This is a simple class holding a precious resource. To make sure that the precious resource is disposed as soon as it is no longer used, the class implements IDisposable (not using the proper full pattern now, to keep the code shorter).

public class NotExceptionSafe : IDisposable
{
    private readonly PreciousResource resource;
 
    public NotExceptionSafe()
    {
        resource = new PreciousResource();
        resource.Open();
    }
 
    public void Dispose()
    {
        resource.Dispose();
    }
}

PreciousResource writes debug output in both the constructor and the Dispose method so we can see that it is properly disposed of. Let’s run the code and test it and see how the resource is allocated and released.

Allocated precious resource.
Caught InvalidOperationException exception (Failed opening!)

Ooopss… it’s only allocated. Then the test runner catches an exception from the Open method.

The problem is that since the NotExceptionSafe instance is never fully constructed it won’t be disposed by the using block (because no object will ever be fully constructed and returned to the using). If the constructor fails, then we’re on our own to handle it.

A better design could remove the problem entirely; never do anything in a constructor that risks throwing. Instead provide a separate Open method. But doing that would totally spoil the point I’m trying to get to, so let’s stick with this design for this post.

To recover from the exception in Open and dispose the resource we won’t get any help from using statements. We’re on our own to handle it.

An Exception Safe Constructor

To show the full power of the pattern I’ll make a slightly more complex case with two instances of the precious resource.

public class ExceptionSafe : IDisposable
{
    private readonly PreciousResource resource1, resource2;
 
    public ExceptionSafe()
    {
        PreciousResource tmp1 = null, tmp2 = null;
        try
        {
            tmp1 = new PreciousResource();
            tmp1.Open();
            tmp2 = new PreciousResource();
            tmp2.Open();
 
            // Commit point, no exception risk any more.
            resource1 = tmp1;
            tmp1 = null;
            resource2 = tmp2;
            tmp2 = null;
        }
        finally
        {
            if (tmp1 != null)
            {
                tmp1.Dispose();
            }
 
            if (tmp2 != null)
            {
                tmp2.Dispose();
            }
        }
    }
 
    public void Dispose()
    {
        resource1.Dispose();
        resource2.Dispose();
    }
}

Now the allocated resource is properly disposed, even though the Open method still throws an exception.

Allocated precious resource.
Disposed precious resource.
Caught InvalidOperationException exception (Failed opening!)

The pattern is quite verbose, but not that complicated. The constructor is now effectively split in three parts.

  1. Do all the constructor work, but don’t touch the members yet. Instead store everything in local temporary variables.
  2. A commit section that assigns the values to the real fields and sets the temporaries to null. It is important to make sure that there is no code that could trigger an exception in or after the commit section.
  3. An finally block that disposes any temporary with a non null value. However far the initialization had come – it will properly dispose of any resource that had been allocated unless the commit section has run and set all temporaries to null.

I’ve shown a constructor here, but the same principle applies to any method that creates IDisposableobjects whose lifetime should last past the method.

Complete source for ExceptionSafe, NotExceptionSafe and PreciousSource classes and the test runner used to run the code.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.