Team LiB   Previous Section   Next Section

18.8 Exception Class Methods and Properties

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 18-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 18-6. Inside the Exception class
using System;

namespace ExceptionHandling
{
   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 (System.DivideByZeroException e)
          {
              Console.WriteLine(
                  "\nDivideByZeroException! Msg: {0}",
                  e.Message);
              Console.WriteLine(
                  "\nHelpLink: {0}", e.HelpLink);
              Console.WriteLine(
                  "\nHere's a stack trace: {0}\n", 
                  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...");           
       }
   }
}

Output:
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 18-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 18.9, 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 (System.DivideByZeroException e)
{
    Console.WriteLine("\nDivideByZeroException! Msg: {0}",
        e.Message);
    Console.WriteLine("\nHelpLink: {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("\nHere's a stack trace: {0}\n", 
    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.

    Team LiB   Previous Section   Next Section