DekGenius.com
[ Team LiB ] Previous Section Next Section

Recipe 5.4 Handling Derived Exceptions Individually

Problem

You have an exception hierarchy that consists of a base exception class and multiple derived exception classes. At some point in your code, you want to handle only one or two of these derived exceptions in a specific manner. All other derived exceptions should be handled in a more generic manner. You need a clean way to target specific exceptions in an exception class hierarchy to be handled differently from the rest.

Solution

The exception handlers for C# allow for multiple catch clauses to be implemented. Each of these catch clauses can take a single parameter—a type derived from the Exception class. An exception handler that uses multiple catch clauses is shown here:

try
{
    int d = 0;
    int z = 1/d;
}
catch(DivideByZeroException dbze)
{
    Console.WriteLine("A divide by zero exception occurred. Error message == "
      + dbze.Message);
}
catch(OverflowException ofe)
{
    Console.WriteLine("An Overflow occurred. Error message == " + ofe.Message);
}
catch(Exception e)
{
    Console.WriteLine("Another type of error occurred. Error message == " 
      + e.Message);
}

This code produces the following output:

A divide by zero exception occurred. Error message == Attempted to divide by zero.

Discussion

Notice the exception types that each catch clause handles in this try-catch block. These specific exception types will be handled on an individual basis within their own catch block. Suppose the try block looked as follows:

try
{
    int z2 = 9999999;
    checked{z2 *= 999999999;}  
}

We would get the following message:

An Overflow occurred. Error message == Arithmetic operation resulted in an overflow.

Now, since the OverflowException is being thrown, it is handled in a totally different catch block.

You may be thinking that you could do the same thing in a single catch block using an if-else statement. An example of this is shown here:

catch(Exception e)
{
    if (e is OverflowException)
        Console.WriteLine("An Overflow occurred. Error message == " + e.Message);
    else if (e is DivideByZeroException)
        Console.WriteLine("A divide by zero exception occurred. Error message == " +
                           e.Message);
    else
        Console.WriteLine("Another type of error occurred. Error message == " + 
                          e.Message);
}

The if-else statements are used to check the type of this exception and then execute the appropriate code. This structure has two flaws. The first is that the compiler does not check whether the exceptions are listed in the correct order in the if-else statements. If an exception class is placed in the if-else conditional structure after a class in which it inherits from, the derived class will never be checked. Consider the following modified catch clause:

try
{
    int d = 0;
    int z = 1/d;
}
catch(Exception e)
{
    if (e is ArithmeticException)
        Console.WriteLine("The base class exception was chosen.");
    else if (e is OverflowException)
        Console.WriteLine("An Overflow occurred. Error message == " + e.Message);
    else if (e is DivideByZeroException)
        Console.WriteLine("A divide by zero exception occurred. Error message == " + 
                           e.Message);
    else
        Console.WriteLine("Another type of error occurred. Error message == " + 
                          e.Message);
}

This code produces the following output:

The base class exception was chosen.

Even though the DivideByZeroException was thrown, the ArithmeticException is always found first, as the DivideByZeroException and OverflowException both have the ArithmeticException class as their base class.

The second flaw is one of appearance. Using multiple catch clauses is much easier to read due to its natural and consistent structure. This is the way the language should be used, and, therefore, this is what many developers are going to look for. Other developers reading your code may find it more natural to read the multiple catch classes rather than the single catch clause with a decision structure inside of it. Not everyone may agree with us on this part, but we do consider structure and consistency an integral part of writing good code.

There is one case where we would consider using the single catch clause with the decision structure: when large amounts of code would have to be duplicated in each catch clause and there is no way to put the duplicated code in a finally clause after the try-catch block.

See Also

See the "Error Raising and Handling Guidelines" topic in the MSDN documentation.

    [ Team LiB ] Previous Section Next Section