Deep C# - Take Exception to Everything
Written by Mike James   
Thursday, 12 March 2020
Article Index
Deep C# - Take Exception to Everything
Catch Clauses
What is an Exception
The State Problem
ThreadException handling

Catch With Details

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:

catch(DivideByZeroException myException)
{
MessageBox.Show(
"division by zero isn't allowed "
+ myException.Source);
}

All exception types are ultimately derived from SystemException.

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.

For example:

try
{
int result = a / b;
}
catch (DivideByZeroException myException)
{
MessageBox.Show(
"division by zero isn't allowed " +
myException.Source);
}
catch (OverflowException)
{
MessageBox.Show("Number too big");
}
finally
{
MessageBox.Show("Something wrong");
}

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.

Banner

Using

The need to clean up after an exception is so common a requirement that there is another way to do it for objects that implement the IDisposable interface.

For example, a common idiom is:

Bitmap B = new Bitmap(10, 10);
try
{
MessageBox.Show(B.Size.ToString());
}
finally
{
if (B != null)
{
((IDisposable)B).Dispose();
}
}

which can also be expressed with using:

Bitmap B;
using(  B = new Bitmap(10, 10))
{
MessageBox.Show(B.Size.ToString());
}

What is more you can have multiple objects within the using statement and create objects within it:

using( Bitmap B = new Bitmap(10, 10))
{
MessageBox.Show(B.Size.ToString());
}

Catch all

If a finally block isn't about doing things that always have to be done how do you handle any exceptions that don't have specific catch clauses?

The solution is to include a catch all clause at the end of the all of the specific catch clauses. For example

try
{
int result = a / b;
}
catch (DivideByZeroException myException)
{
MessageBox.Show(
"division by zero isn't allowed " +
myException.Source);
}
catch (OverflowException)
{
MessageBox.Show("Number too big");
}
catch
{
MessageBox.Show("something else wrong");
}
finally
{
MessageBox.Show("Something wrong");
}

If none of the other catch clauses handle the exception then the final catch and the finally are executed.

If you place the general catch clause higher in the list of catch clauses then you will see a compile time error message to the effect that you can't have specific catches after a general one.

This is an example of the more general rule that more specific catch clauses have to come before more general ones. The reason is that as soon as a catch clause matches the type specification the try catch is complete and no more catch clauses are checked. So a more general catch clause occurring before a more specific one means that the more specific one will never be used.

Banner



Last Updated ( Thursday, 12 March 2020 )