Structured exception handling sounds like a really good idea until you start to look at it more closely - then it almost becomes worse than the problem it is trying to solve. We look at exception handling the philosophy, the strategy and the way C# does the job.

Once upon a time we wrote programs that worked and they were designed not to crash.

Of course this is a fairy story and what we actually did was to write programs that worked as long as nothing unusual happened - that is as long as the input and operating conditions were as "expected" by the programmer.

If this wasn’t the case well - what could you expect - the program was broken and beyond our control. The runtime system generally ended the program with an "abnormal end" or "abend".

Of course today this would be a ridiculous way to handle errors but programs still fail at runtime because eliminating runtime errors is still usually something of an afterthought.

The solution to the problem is generally accepted to be structured exception handling - that is try-catch to you and me. However the whole subject is trickier than you might imagine.

Let's take a look at how it all works and how it all might be made to work.

Try-catch

The basic syntax and operation of exception handling is very simple.

You surround any block of code that you think might fail with a try clause. If something does go wrong the block of code generates, or throws, an exception which is caught by the catch clause.

In this case it is clear that b is zero and so a/b cannot be computed and so the CLR throws a runtime exception. This is caught by the catch clause and the message is displayed.

This is a very common way to use the try-catch but it has a problem.

Suppose the exception is caused by something other than a divide by zero error. The catch clause operates no matter what the problem is with the try block leading the user and the programmer trying to fix the problem to believe that it is a division by zero problem. The solution is to always specify what exception you are handling with a conditional catch clause.

Notice that the catch clause now only handles exceptions of type DivideByZeroException.

The idea of using types to define exceptions is a perfectly reasonable one as many exceptions include an object of the specified type customised with details of the exception. If you need to process the exception object just include it as a parameter in the catch:

If you don't need the exception object don't include it in the catch - just the type. Notice also that derived types match the parent type. So for example, all exceptions match the SystemException type specification.

Of course you can have multiple catch clauses, each dealing with a different type of exception and there is always the finally clause, which is always executed whether or not an exception occurs.

This now handles two types of exception - divide by zero and overflow - but whichever happens the finally clause always displays "Something might be wrong" even if an exception has been handled by one of the previous clauses.

It is important to realise that the finally clause isn't a catch-all that handles any exception that you can't be bothered to write a specific catch clause for. Its purpose is to ensure that code is executed irrespective of whether or not an exception occurs.

Typically this code does a clean up job that is specific to the code in the try block - e.g. it closes files that are no longer used or disposes of other resources that might have been created.

It is also worth knowing that a try block can have a finally even if it doesn't have any catch blocks simply to do a clean up job after the system has displayed a default error message.

Another interesting situation that often puzzles the newcomer to exception handing is the simple fact that any variables declared in the try block are local to that block. Similarly any objects created in the block cannot be used within a catch or finally block because the compiler generates an initialised local variable error. What this means is that any objects or variables that you plan to use within the clauses of a try-catch have to be created outside of the block.