One of the common mistakes I see in beginner programmers is a lack of understanding around exceptions and how to handle them. Two years ago I started working on a project where every single server-side method (accessed via a remoting call) was surrounded by a try-catch block. When I discussed this with the project leader I was told that this was a done to “prevent the application from crashing when an exception occurs”. If you have seen code like this or you are simply unsure of when to handle exceptions, read on.
What happens to our application when an Unhandled Exception occurs?
To get started, let’s create an application and see what happens when an exception occurs. I created a simple WinForms application that throws an exception when I click a button.
If you run this from within Visual Studio you should get a message informing you that an unhandled exception has occurred. If you run this from outside Visual Studio you will either get the same message from the JIT-compiler or the application will simply disappear. In short, the application is crashing due to the unhandled exception.
So can we prevent the application from crashing without having to wrap every single method in a try-catch block? The answer is quite tricky. There is an interesting article on MSDN that explains it quite well – here are a few excerpts from the article.
- Unhandled exceptions that occur on the application’s main thread cause the application to terminate
- Unhandled exceptions that occur in threads other than the application’s main thread are swallowed by the CLR and can be displayed in a manner of your choosing
Let’s take a look at how I would handle the exception that is occurring in the sample application.
Handling Exceptions in a WinForms application
The .NET framework exposes 2 events to allow us to handle exceptions at the application level. This is usually the first thing I do when I create a WinForms application.
If I re-run the sample application I now get a message showing the exception and the stack trace. More importantly, the application keeps running!
You probably want to write a form for displaying this information to the user in a consistent fashion.
So when should we handle exceptions?
So now that we have a mechanism for handling exceptions at the application level we need to decide when to throw and when to handle exceptions. The golden rule for deciding when to throw exceptions is that exceptions should be exceptional. Simply ask yourself if this is truly an exceptional case and you should have a pretty good idea of whether to throw an exception or not.
If the config file is missing or corrupt – that’s exceptional. If the application can’t establish a connection to the database – that’s exceptional. If the user mistypes his password – that’s not exceptional. (Although if he/she mistypes it more that a certain threshold limit – that’s exceptional)
And now for the other side of the coin – when should we handle exceptions? There is another golden rule I try to adhere to for exception handling – only catch exceptions that you are able to handle. To clarify, here is another extract from the MSDN article:
There are only a miniscule number of cases in which your code can be sure that it knows how to appropriately handle any possible exception that escapes a try block. There are far more unexpected exception cases than you might imagine. In managed code, even code that doesn’t call any methods could throw a variety of exceptions, including security exceptions, out-of-memory exceptions, execution-engine exceptions, and the like. It is best for your applications to always catch specific exceptions and leave all other unexpected exceptions as unhandled.
This rule dictates that you should never catch System.Exception. Once you get used doing exception handling in this way you will notice that you mostly either handle exceptions to add extra information to the exception or execute a different block of code depending on the occurrence of a specific type of exception.
I think the tricky part of exception management is that you need to evaluate every situation on a case-by-case basis. This simply means that experience is quite influential in making a decision in each scenario. But that’s what programming is all about!
Keep in mind that you don’t need to break your back to stick to the rules I have outlined here – after all, there are exceptions to every rule! Happy coding.