The using statement is short and concise but does get in the way writing clean code. Do not use it.

I found that my colleagues and I were using the C# using statement as a replacement for try/catch blocks because we assumed it automatically and magically handled exceptions safely. Of course whenever you assume magic in programming, you don’t know what you’re doing and you inadvertently do it wrong.

In actuality, the using statement does no such thing as handling exceptions. It can even hide exceptions from you!

The C# reference explains that the compiler expands a using block into a try/finally block.

This means that a using block like this one

using (<create instance>)
{
	<use instance>
}

is turned into this:

{
	<create instance>
	try
	{
		<use instance>
	}
	finally
	{
		if (instance != null)
			((IDisposable)instance).Dispose();
	}
}

(Note the if block without braces – a pet peeve of mine.)

As you can see there is no catch block. Exceptions are not handled at all. All the using statement does is guarantee that Dispose() is called if an exception occurs inside the using block. Note that the instance creation itself is not inside the try block. This makes sense because the Dispose() method cannot be called if the instance has not been created successfully.

So What Happens If An Exception Is Thrown?

There are three different locations from which exceptions might be thrown:

  • during instance creation
  • from the try block
  • from the finally block

In each of these cases the exception will be passed up the stack trace as expected. So one might be tempted to handle exceptions like this:

try
{
	using(<create instance>)
	{
		<use instance>
	}
}
catch(Exception x)
{
	<handle exception>
}

There are two problems with this approach:

  • If an exception is thrown from within the using statement’s try block, and then another exception is thrown in the using statement’s finally block, then the first exception is lost and you won’t be able to catch it.
  • The instance is not accessible for exception handling. This is arguably a feature of the using statement but does nothing good for logging or debugging.

The first problem is big enough for me to never use the using statement again – in production code or elsewhere. Imagine a using statement that instantiates a stream, then throws an exception while manipulating the stream, and then also throws an exception when closing the stream. How many hours or days will it take you to discover that the real exception was hidden from you?

I don’t understand why the using statement is part of the C# language. It virtually forces the developer to write sloppy code. The MSDN page I linked to above begins with the assertion that the using statement “Provides a convenient syntax that ensures the correct use of IDisposable objects.” This may be true, but if you consider that the Stream class implements IDisposable as well, this is setting developers up for failure.

So What Is the Correct Replacement For the Using Statement?

Well, if you want to play it safe, you will have to use this construct instead:

try
{
	<create instance>
	<use instance>
}
catch(Exception x)
{
	<handle exception>
}
finally
{
	try
	{
		<dispose of instance if not null>
	}
	catch (Exception x)
	{
		<handle exception>
	}
}

This is tiny bit more verbose than the using statement at the beginning of this article and it does make it a bit harder to read the “normal” flow of the program. For convenient debugging or logging you will have to declare the instance variable before the try block. This is a little ugly because then it is visible even after the finally block.

P.S.: I wanted to call this article “Using Statement Considered Harmful” but after reading this great article I decided against it.

Advertisements