Free mag vol1 | Page 335

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