CHAPTER 7 UNDERSTANDING STRUCTURED EXCEPTION HANDLING
system-supplied error dialog box. Typically, you would only rethrow a partial handled exception to a
caller that has the ability to handle the incoming exception more gracefully.
Notice as well that we are not explicitly rethrowing the CarIsDeadException object, but rather
making use of the throw keyword with no argument. We’re not creating a new exception object; we’re
just rethrowing the original exception object (with all its original information). Doing so preserves the
context of the original target.
Inner Exceptions
As you might suspect, it is entirely possible to trigger an exception at the time you are handling another
exception. For example, assume you are handling a CarIsDeadException within a particular catch scope,
and during the process you attempt to record the stack trace to a file on your C: drive named
carErrors.txt (you must specify you are using the System.IO namespace to gain access to these I/Ocentric types):
catch(CarIsDeadException e)
{
// Attempt to open a file named carErrors.txt on the C drive.
FileStream fs = File.Open(@"C:\carErrors.txt", FileMode.Open);
...
}
Now, if the specified file is not located on your C: drive, the call to File.Open() results in a
FileNotFoundException! Later in this text, you will learn all about the System.IO namespace where you’ll
discover how to programmatically determine whether a file exists on the hard drive before attempting to
open the file in the first place (thereby avoiding the exception altogether). However, to stay focused on
the topic of exceptions, assume the exception has been raised.
When you encounter an exception while processing another exception, best practice states that you
should record the new exception object as an “inner exception” within a new object of the same type as
the initial exception. (That was a mouthful!) The reason you need to allocate a new object of the
exception being handled is that the only way to document an inner exception is via a constructor
parameter. Consider the following code:
catch (CarIsDeadException e)
{
try
{
FileStream fs = File.Open(@"C:\carErrors.txt", FileMode.Open);
...
}
catch (Exception e2)
{
// Throw an exception that records the new exception,
// as well as the message of the first exception.
throw new CarIsDeadException(e.Message, e2);
}
}
Notice in this case, we have passed in the FileNotFoundException object as the second parameter to
the CarIsDeadException constructor. After we have configured this new object, we throw it up the call
stack to the next caller, which in this case would be the Main() method.
275