What’s up with ‘using’?

Let me lay my cards on the table right from the start: I don’t like using, and I don’t use it any more (no pun intended). In fact I haven’t for quite some time. In this post I’m going to try to explain why I don’t use it, and why I don’t think you should either.

When you first encounter using, it seems like a great little timesaver. You write some code like this (the logic is just there for illustration, and in any case is not the best performing way to read an entire file):

using ( FileStream stream = new FileStream(
    somePathName,
    FileMode.Open,
    FileAccess.Read,
    FileShare.Read ) )
{
    while ( stream.ReadByte() >= 0 ); // Stream reading logic here
}

And the compiler turns it into something like this:

FileStream stream = new FileStream(
    somePathName,
    FileMode.Open,
    FileAccess.Read,
    FileShare.Read );
try
{
    while ( stream.ReadByte() >= 0 ); // Stream reading logic here
}
finally
{
    stream.Dispose();
}

Fantastic! If an exception is thrown by my stream reading logic the FileStream will still be disposed of and the file closed, and I’ve had to do less typing to ensure that happens.

In a more realistic situation you might choose to wrap the using block in a try..catch statement that deals with FileNotFoundException, IOException, UnauthorisedAccessException, and the rest, and provides the user with a helpful error if something goes wrong, but basically it’s all good.

Isn’t it?

Weeeelllll…. not quite as much as you might think.

Before going any further I will say it’s a big improvement over this:

FileStream stream = new FileStream(
    somePathName,
    FileMode.Open,
    FileAccess.Read,
    FileShare.Read );
while ( stream.ReadByte() >= 0 ); // Stream reading logic here
stream.Dispose(); // Or stream.Close(), doesn’t really matter

With this code, if your stream reading logic throws an exception, the file won’t be closed until the FileStream is finalised, which might happen immediately, or might not happen until, well, goodness knows really. The point is that until it does other processes may not be able to access the file, depending upon what they’re trying to do: in this case reading would be okay but trying to open the file for writing would fail. Potentially this could be catastrophic, at least for your software; if your code is running in a hospital, aboard an aircraft, or inside a nuclear power plant it could really be catastrophic, so don’t say I didn’t warn you.

Getting back to the code generated by the compiler for your using block, let’s say again that the logic in the try block throws an IOException of some sort. In the normal case your finally block will execute, the FileStream will be disposed of, and the file will be closed, making it available to other threads or processes. But what about the abnormal case: what happens if the Dispose() method throws an exception? Then you could be in some trouble.

“But wait!” I hear you cry, “Implementations of Dispose() shouldn’t throw any exceptions!” Now I’m pretty sure I remember hearing somebody-a speaker-say exactly that at a conference a few years back, and I’m also pretty sure I remember them saying that this was what Microsoft say should happen. In an ideal world that would be great but given the complexity of the .NET framework it’s just not realistic, and if you read the MSDN documentation for IDisposable there’s not even a hint that this might be the case, at least for .NET 2.0, so I’m going to brand this assertion wishful thinking.

To prove it let’s take a look at the Dispose() method on FileStream, which is inherited, and follows the expected pattern by calling the virtual Dispose( bool ) method. This in turn calls FileStream.FlushWrite() which most assuredly can throw exceptions, the most obvious of which are IOException and its subclasses. So whilst it might be a rare occurrence, it’s certainly a fallacy to think that you’re never going to run into a situation where Dispose() throws an exception.

Now if Dispose() does throw an exception, it will mask the exception thrown from the try block. At the very least this is likely to cause you some inconvenience whilst debugging, but if, for example, the exceptions are of different types, you could find yourself in side-effect city if you handled one but not the other, or had handlers at different levels in your code. In production code this is not a great situation.

Fortunately there is a solution, although you may not like it. Truthfully I don’t particularly like it either because it’s comparatively verbose: I’m lazy so the idea of using has quite a strong appeal. Anyway, here it is:

FileStream stream = null;
try
{
    stream = new FileStream(
        somePathName,
        FileMode.Open,
        FileAccess.Read,
        FileShare.Read );
    while ( stream.ReadByte() >= 0 ); // Stream reading logic here
    stream.Dispose();
    stream = null;
}
finally
{
    if ( stream != null )
    {
        try { stream.Dispose(); } catch ( Exception ) {}
    }
}

Note that I’ve initialised the stream inside the try block because in this simple case I’d probably just handle any exceptions by adding catch blocks to this try..finally statement. If you need finer grained control and want to handle exceptions occurring whilst trying to open the file separately, you could place the initialisation just before the try block-just like the compiler when it expands using-and then wrap the whole lot in another try..catch statement.

What happens here is that in the normal case the stream is created, used, and cleaned up in the try block. The test in the finally block always evaluates to false, and the second call to Dispose() is not executed. On the other hand if an exception is thrown anywhere in the try block after stream is initialised the Dispose() method will be invoked in the finally block and any CLR exception it throws will be swallowed. If stream hasn’t been initialised the test will again fail and the call to Dispose() won’t be made. Thus, exceptions can be thrown by the stream reading logic, or the Dispose() call, but an exception thrown by Dispose() will never mask an exception thrown earlier on in the stream reading logic. If you see an exception thrown by Dispose() it’s a ‘real’ exception neither (indirectly) caused by, nor masking, a previously thrown exception.

Note that in general it’s very bad form-actually it’s just a bad idea-to catch general exception types (Exception, ApplicationException), or to catch everything including non-CLR exceptions, but in this case the Dispose() method in the finally block is only executed in the event that an exception has already been thrown so this is okay because you’re going to be much more interested in the first exception.

And that’s it. What I’ve actually shown here is a specific instance of a general problem with finally blocks-exceptions thrown in a finally block can hide an exception thrown elsewhere-but here a solution is available. It’s certainly more verbose-and perhaps just a wee bit anal retentive-but in the worst case it’s a much safer scenario than trusting using to do your cleanup for you.

Take home message: don’t use using.