C# Exception best practices

Here are some good practices for dealing with exceptions in C#, and by extension .Net. While the post title says best practices, I’m using the term good practice here because I do not have the pretension that these are the best practices available or that all best or good practices are presented herein.

Why use the word best rather than good in the title? I’d be surprised if anyone searched google for exception good practices, that’s why.

Here they are.

Don’t use ApplicationException

ApplicationException was created as a standard base class from which all our applications custom exceptions should derive from. All framework system exceptions would derive from SystemException. This was made to allow us for instance, to catch only our application’s exception.

There are three problems with this premise. First, the rule was not followed. Some exceptions like System.Reflection.TargetInvocationException or System.Threading.WaitHandleCannotBeOpenedException derive from ApplicationException (there’s a total of eight of them), which means you can’t use the fact that an exception derives from ApplicationException to differentiate it as one of your own.

The MSDN documentation about ApplicationException and Best Practices for Handling Exceptions both proscribe using it for another reason.

The second point against ApplicationException, as brought by these links, is that differentiating application exceptions has been shown to be of little value. I agree with this. If I have a method that can throw a custom exception or a framework exception (ie: an exception from a .Single() LINQ extension method), I will want to handle both in the same way.

Third, I have often seen people use ApplicationException directly rather than derive from it. This leads to people being lazy and using the generic ApplicationException (which is about the same as using Exception) rather than a more precise one, like ArgumentNullException or ArgumentOutOfRangeException for example.

Also Krzysztof Cwalina on his blog declared the exception as useless: ApplicationException considered useless. If you haven’t heard about Cwalina, he’s a principal architect on the .NET Framework team.

Rethrowing Exceptions

If you need to rethrow an exception in your catch block this is the right way to do it:

// correct way to rethrow an exception
try
{
    Foo(); // Foo calls Bar which throws InvalidOperationException
}
catch (Exception exception)
{
    // do stuff 
    throw;
}

as opposed to this:

// wrong way to rethrow an exception
try
{
    Foo(); // Foo calls Bar which throws InvalidOperationException
}
catch (Exception exception)
{
    // do stuff 
    throw exception;
}

The only change is on the line that throws the exception.

The difference is that in the first version the callstack is preserved where in the second version it starts where the method is called.

Compare the two:

System.InvalidOperationException was unhandled
  HResult=-2146233079
  Message=Operation is not valid due to the current state of the object.
  Source=ExceptionBlog
  StackTrace:
       at ExceptionBlog.Exception1.Bar() in \...\Exception1.cs:line 12
       at ExceptionBlog.Exception1.Foo() in \...\Exception1.cs:line 17
       at ExceptionBlog.Exception1.Rethrow() in \...\Exception1.cs:line 28
       ...

and

System.InvalidOperationException was unhandled
  HResult=-2146233079
  Message=Operation is not valid due to the current state of the object.
  Source=ExceptionBlog
  StackTrace:
       at ExceptionBlog.Exception1.Rethrow() in \...\Exception1.cs:line 28
       ...

Don’t use exceptions as a control flow mechanism

Reserve exceptions for exceptional and unexpected situations. Sometimes you will see exceptions being used as a control flow mechanism, just like if statements.

For example, say you have a system that handles employee records. In the vast majority of cases employees will be 16 years or older. In rare situations in your business domain you have special cases where an employee is younger than this. In these case your system must show a warning that the employee must get a parent/tutor approbation before signing a certain document.

Here you could use an exception that deals with those rare cases. The thing is you know these cases can happen and you expect them to happen infrequently.

In these cases using a normal control flow statement rather than an exception is more idiomatic and often clearer to the reader. Exceptions are also slower than control flow statements. Finally in this example you will be treating a business case in the exception handling code. It is better to separate the two concerns.

Using the same base example, a situation that would merit an exception is the system receiving an employee id and not being able to return an employee from the data source with said id.

Exception variable name

This next one may seem very minor. In some sense it is, but this is the kind of subtle detail that adds up and help make code cleaner.

We aren’t writing code for computers but for human readers. The computer is fine with assembler. We as writers and readers of code are better off with a higher level language. Not only for the level of abstraction it provides but for the higher maintainability of readable code. Readability is important.

Readable code is faster to comprehend and easier to discuss aloud with colleagues. This is why abbreviations and acronyms in variable names should be avoided.

Even with proponents of self documenting code, there are some areas that are sometimes ignored. The name of the exception variable is one of those.

catch (Exception e)

While e or ex is understood by anyone, why not put in the extra effort to at least write

catch (Exception exception)

or better yet an even better and more descriptive name. With auto complete you will just have to type it in once anyway.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s