CHAPTER 7 UNDERSTANDING STRUCTURED EXCEPTION HANDLING
This exception-handling logic generates compile-time errors. The problem is due to the fact that the
first catch block can handle anything derived from System.Exception (given the “is-a” relationship),
including the CarIsDeadException and ArgumentOutOfRangeException types. Therefore, the final two
catch blocks are unreachable!
The rule of thumb to keep in mind is to make sure your catch blocks are structured such that the
very first catch is the most specific exception (i.e., the most derived type in an exception-type
inheritance chain), leaving the final catch for the most general (i.e., the base class of a given exception
inheritance chain, in this case System.Exception).
Thus, if you want to define a catch block that will handle any errors beyond CarIsDeadException and
ArgumentOutOfRangeException, you could write the following:
// This code compiles just fine.
static void Main(string[] args)
{
Console.WriteLine("***** Handling Multiple Exceptions *****\n");
Car myCar = new Car("Rusty", 90);
try
{
// Trigger an argument out of range exception.
myCar.Accelerate(-10);
}
catch (CarIsDeadException e)
{
Console.WriteLine(e.Message);
}
catch (ArgumentOutOfRangeException e)
{
Console.WriteLine(e.Message);
}
// This will catch any other exception
// beyond CarIsDeadException or
// ArgumentOutOfRangeException.
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Console.ReadLine();
}
Note Where at all possible, always favor catching specific exception classes, rather than a general
System.Exception. Though it might appear to make life simple in the short term (you may think, “Ah! This catches
all the other things I don’t care about.”), in the long term you could end up with strange runtime crashes, as a
more serious error was not directly dealt with in your code. Remember, a final catch block that deals with
System.Exception tends to be very general indeed.
273