[ Team LiB ] Previous Section Next Section

11.2 Exception Objects

So far you've been using the exception as a sentinel—that is, the presence of the exception signals the error—but you haven't touched or examined the Exception object itself. The System.Exception object 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 set the Message property as an argument to the exception constructor.

The HelpLink property provides a link to the help file associated with the exception. This property is read/write.

VB6 programmers take note: In C#, you need to be careful when declaring and instantiating object variables on the same line of code. If there is a possibility that an error could be thrown in the constructor method, then you might be temped to put the variable declaration and instantiation inside the try block. But if you do that, the variable will only be scoped within the try block and it can't be referenced within the catch or finally blocks. The best approach is to declare the object variable before the try block and instantiate it within the try block.

The StackTrace property is read-only and is set by the runtime. In Example 11-6, the Exception.HelpLink property is set and retrieved to provide information to the user about the DivideByZeroException. The StackTrace property of the exception is used to provide a stack trace for the error statement. A stack trace displays the call stack: the series of method calls that lead to the method in which the exception was thrown.

Example 11-6. Working with an exception object
namespace Programming_CSharp
{
    using System;

    public class Test
    {
        public static void Main( )
        {
            Test t = new Test( );
            t.TestFunc( );
        }

        // try to divide two numbers
        // handle possible exceptions
        public void TestFunc( )
        {
            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;
        }
    }
}

Output:
Open file here

DivideByZeroException! Msg: Attempted to divide by zero.

HelpLink: http://www.libertyassociates.com

Here's a stack trace:    
at Programming_CSharp.Test.DoDivide(Double a, Double b)
 in c:\...exception06.cs:line 56
at Programming_CSharp.Test.TestFunc( ) 
in...exception06.cs:line 22

Close file here.

In the output, the stack trace lists the methods in the reverse order in which they were called; that is, it shows that the error occurred in DoDivide( ), which was called by TestFunc( ). When methods are deeply nested, the stack trace can help you understand the order of method calls.

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 will be printed:

DivideByZeroException! Msg: Attempted to divide by zero.

You can modify this line of code to pass in a default message:

new DivideByZeroException(
  "You tried to divide by zero which is not meaningful");

In this case, the output message will reflect 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, the program prints the message and the HelpLink:

catch (System.DivideByZeroException e)
{
    Console.WriteLine("\nDivideByZeroException! Msg: {0}",
        e.Message);
    Console.WriteLine("\nHelpLink: {0}", e.HelpLink);

This allows you to provide useful information to the user. In addition, it 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:

Here's a stack trace:    
at Programming_CSharp.Test.DoDivide(Double a, Double b)
 in c:\...exception06.cs:line 56
at Programming_CSharp.Test.TestFunc( ) 
in...exception06.cs:line 22

Note that I've shortened the pathnames, so your printout might look a little different.

    [ Team LiB ] Previous Section Next Section