Is there a situation in which Dispose won't be called for a 'using' block?

This was a telephone interview question I had: Is there a time when Dispose will not be called on an object whose scope is declared by a using block?

My answer was no - even if an exception happens during the using block, Dispose will still be called.

The interviewer disagreed and said if using is wrapped in a try-catch block then Dispose will not be called by the time you enter the catch block.

This goes contrary to my understanding of the construct, and I haven't been able to find anything that backs up the interviewers point of view. Is he correct or might I have misunderstood the question?


Solution 1:

Four things that will cause Dispose to not be called in a using block:

  1. A power failure on your machine when inside the using block.
  2. Your machine getting melted by an atomic bomb while in the inside of the using block.
  3. Uncatchable exceptions like StackOverflowException, AccessViolationException and possibly others.
  4. Environment.FailFast

Solution 2:

void Main()
{
    try
    {
        using(var d = new MyDisposable())
        {
            throw new Exception("Hello");
        }
    }
    catch
    {
        "Exception caught.".Dump();
    }

}

class MyDisposable : IDisposable
{
    public void Dispose()
    {
        "Disposed".Dump();
    }
}

This produced :

Disposed
Exception caught

So I agree with you and not with the smarty interviewer...

Solution 3:

Bizarrely I read about a circumstance where Dispose won't get called in a using block just this morning. Checkout this blog on MSDN. It's around using Dispose with IEnumerable and the yield keyword, when you don't iterate the entire collection.

Unfortunately this doesn't deal with the exception case, honestly I'm not sure about that one. I would have expected it to be done but maybe it's worth checking with a quick bit of code?

Solution 4:

The other answers about power failure, Environment.FailFast(), iterators or cheating by using something that is null are all interesting. But I find it curious that nobody mentioned what I think is the most common situation when Dispose() won't be called even in the presence of using: when the expression inside using throws an exception.

Of course, this is logical: the expression in using threw an exception, so the assignment didn't take place and there is nothing we could call Dispose() on. But the disposable object can already exist, although it can be in half initialized state. And even in this state it can already hold some unmanaged resources. This is another reason why correctly implementing the disposable pattern is important.

Example of the problematic code:

using (var f = new Foo())
{
    // something
}

…

class Foo : IDisposable
{
    UnmanagedResource m_resource;

    public Foo()
    {
        // obtain m_resource

        throw new Exception();
    }

    public void Dispose()
    {
        // release m_resource
    }
}

Here, it looks like Foo releases m_resource correctly and we are using using correctly too. But the Dispose() on Foo is never called, because of the exception. The fix in this case is to use finalizer and release the resource there too.