So far you’ve been using the exception as a sentinel—that
is, the presence of the exception signals the errors—but you haven’t
touched or examined the Exception
object itself. The System.Exception
class provides a number of useful methods and properties.
The Message
property provides information about the exception, such
as why it was thrown. The Message
property is read-only; the code throwing the exception can pass in the
message as an argument to the exception constructor, but the Message
property cannot be modified by any
method once set in the constructor.
The HelpLink
property provides a link to a help file associated with
the exception. This property is read/write. In Example 16-6, the Exception.HelpLink
property is set and
retrieved to provide information to the user about the DivideByZeroException
. It is generally a good
idea to provide a help file link for any exceptions you create, so that
the user can learn how to correct the exceptional circumstance.
The read-only StackTrace
property is set by the CLR. This property is used to
provide a stack trace for the error statement. A
stack trace is used to display the call stack: the series of method
calls that lead to the method in which the exception was thrown.
Example 16-6. Inside the Exception class
using System; namespace InsideTheExceptionClass { class Tester { public void Run( ) { try { Console.WriteLine( "Open file here" ); double a = 12; double b = 0; Console.WriteLine( "{0} / {1} = {2}", a, b, DoDivide( a, b ) ); Console.WriteLine( "This line may or may not print" ); } // most derived exception type first catch (DivideByZeroException e ) { Console.WriteLine( " DivideByZeroException! Msg: {0}", e.Message ); Console.WriteLine( " HelpLink: {0}", e.HelpLink ); Console.WriteLine( " Here's a stack trace: {0} ", e.StackTrace ); } catch { Console.WriteLine( "Unknown exception caught" ); } finally { Console.WriteLine( "Close file here." ); } } // do the division if legal public double DoDivide( double a, double b ) { if ( b == 0 ) { DivideByZeroException e = new DivideByZeroException( ); e.HelpLink = "http://www.libertyassociates.com"; throw e; } if ( a == 0 ) throw new ArithmeticException( ); return a / b; } static void Main( ) { Console.WriteLine( "Enter Main..." ); Tester t = new Tester( ); t.Run( ); Console.WriteLine( "Exit Main..." ); } } }
The output looks like this:
Enter Main... Open file here DivideByZeroException! Msg: Attempted to divide by zero. HelpLink: http://www.libertyassociates.com Here's a stack trace: at ExceptionHandling.Tester.DoDivide(Double a, Double b) in class1.cs:line 54 at ExceptionHandling.Tester.Run( ) in class1.cs:line 14 Close file here. Exit Main...
In the output of Example
16-6, the stack trace lists the methods in the reverse order in
which they were called; by reviewing this order, you can infer that the
error occurred in DoDivide( )
, which
was called by Run( )
. When methods
are deeply nested, the stack trace can help you understand the order of
method calls and thus track down the point at which the exception
occurred.
In this example, rather than simply throwing a DivideByZeroException
, you create a new
instance of the exception:
DivideByZeroException e = new DivideByZeroException( );
You do not pass in a custom message, and so the default message is printed:
DivideByZeroException! Msg:Attempted to divide by zero.
The designer of each Exception
class has the option to provide a
default message for that exception type. All the standard exceptions
provide a default message, and it is a good idea to add a default
message to your custom exceptions as well (see the section "Custom Exceptions,” later
in this chapter).
If you want, you can modify this line of code to pass in a custom message:
new DivideByZeroException( "You tried to divide by zero which is not meaningful");
In this case, the output message reflects the custom message:
DivideByZeroException! Msg: You tried to divide by zero which is not meaningful
Before throwing the exception, set the HelpLink
property:
e.HelpLink = "http://www.libertyassociates.com";
When this exception is caught, Console.WriteLine
prints both the Message
and the HelpLink
:
catch (DivideByZeroException e) { Console.WriteLine(" DivideByZeroException! Msg: {0}", e.Message); Console.WriteLine(" HelpLink: {0}", e.HelpLink);
The Message
and HelpLink
properties allow you to provide
useful information to the user. The exception handler also prints the
StackTrace
by getting the StackTrace
property of the Exception
object:
Console.WriteLine(" Here's a stack trace: {0} ", e.StackTrace);
The output of this call reflects a full StackTrace
leading to the moment the exception
was thrown. In this case, only two methods were executed before the
exception, DoDivide( )
and Run( )
:
Here's a stack trace: at ExceptionHandling.Tester.DoDivide(Double a, Double b) in class1.cs:line 54 at ExceptionHandling.Tester.Run( ) in class1.cs:line 14
Note that I’ve shortened the pathnames, so your printout might look a little different.