13.7 Exception Properties

As we discussed in Section 13.4, exception types derive from class Exception, which has several properties. These frequently are used to formulate error messages indicating a caught exception. Two important properties are Message and StackTrace. Property Message stores the string error message associated with an Exception object. This message can be a default message defined in the exception type or a customized message passed to an Exception object’s constructor when the Exception object is thrown. Property Stack-Trace contains a string that represents the method-call stack. Recall that the runtime environment at all times keeps a list of open method calls that have been made but have not yet returned. The StackTrace represents the series of methods that have not finished processing at the time the exception occurs. If the debugging information that’s generated by the compiler for the method is accessible to the IDE (e.g., the code is part of your project, rather than some third party library), the stack trace also includes line numbers; the first line number indicates the throw point, and subsequent line numbers indicate the locations from which the methods in the stack trace were called.

13.7.1 Property InnerException

Another frequently used property is InnerException. When an exception occurs in a class library, it’s common for the library to catch that exception, then throw a new one containing information that helps the client code programmer determine the exception’s cause. Class library programmers typically “wrap” the original exception object in the new exception object—this gives the client code programmer complete details of what led to the exception.

For example, a programmer implementing libraries used in an accounting system might have account-number processing code in which account numbers are input as

strings but represented as ints in the code. Recall that a program can convert strings to int values with int.Parse, which throws a FormatException if it encounters an invalid number format. When this happens, the library programmer might wish to employ a different error message than the default message supplied by FormatException or might wish to indicate a new exception type, such as InvalidAccountNumberException.

In such cases, the library programmer would provide code to catch the FormatException, then create an InvalidAccountNumberException object in the catch block, passing the original exception as a constructor argument. The original exception object becomes the InvalidAccountNumberException object’s InnerException. Section 13.8 shows how to create a custom exception class.

When an InvalidAccountNumberException occurs in code that uses the accounting-system library, the catch handler can reference the original exception via property Inner-Exception. So the InvalidAccountNumberException can indicate both that the user specified an invalid account number and that the number format was invalid. If the InnerException property is null, this indicates that the exception was not caused by another exception.

13.7.2 Other Exception Properties

Class Exception provides other properties, including HelpLink, Source and TargetSite:

  • Property HelpLink specifies a link to the help file that describes the problem that occurred. This property is null if no such file exists.

  • Property Source specifies the name of the assembly (i.e., app or library) that caused the exception.

  • Property TargetSite specifies the method where the exception originated.

13.7.3 Demonstrating Exception Properties and Stack Unwinding

Our next example (Fig. 13.5) demonstrates properties Message, StackTrace and Inner-Exception of class Exception. In addition, the example formally introduces stack unwinding—when an exception is thrown but not caught in a particular scope, the method-call stack is “unwound,” and an attempt is made to catch the exception in the next outer try block. We keep track of the methods on the call stack as we discuss property Stack-Trace and the stack-unwinding mechanism. To see the proper stack trace, you should execute this program using steps similar to those presented in Section 13.2..

Fig. 13.5 Stack unwinding and Exception class properties.

Alternate View

  1    // Fig. 13.5: Properties.cs
  2    // Stack unwinding and Exception class properties.
  3    // Demonstrates using properties Message, StackTrace and InnerException.
  4    using System;
  5
  6    class Properties
  7    {
  8       static void Main()
  9       {
 10          // call Method1; any Exception generated is caught
 11          // in the catch block that follows
 12          try
 13          {
 14             Method1();
 15          }
 16          catch (Exception exceptionParameter)
 17          {
 18              // output the string representation of the Exception, then output
 19              // properties Message, StackTrace and InnerException
 20              Console.WriteLine("exceptionParameter.ToString: 
" +
 21                 exceptionParameter);
 22              Console.WriteLine("
exceptionParameter.Message: 
" +
 23                 exceptionParameter.Message);
 24              Console.WriteLine("
exceptionParameter.StackTrace: 
" +
 25                 exceptionParameter.StackTrace);
 26              Console.WriteLine("
exceptionParameter.InnerException: 
" +
 27                 exceptionParameter.InnerException);
 28
 29       }
 30
 31       // calls Method2
 32       static void Method1()
 33       {
 34          Method2();
 35       }
 36
 37       // calls Method3
 38       static void Method2()
 39       {
 40          Method3();
 41       }
 42
 43       // throws an Exception containing an InnerException
 44       static void Method3()
 45       {
 46          // attempt to convert string to int
 47          try
 48          {
 49             int.Parse("Not an integer");
 50          }
 51          catch (FormatException formatExceptionParameter)
 52          {
 53              // wrap FormatException in new Exception
 54              throw new Exception("Exception occurred in Method3",
 55                 formatExceptionParameter);                       
 56          }
 57       }
 58    }

             exceptionParameter.ToString:
             System.Exception: Exception occurred in Method3 --->
                System.FormatException: Input string was not in a correct format.
                at System.Number.StringToNumber(String str, NumberStyles options,
                   NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
                at System.Number.ParseInt32(String s, NumberStyles style,
                   NumberFormatInfo info)
                at System.Int32.Parse(String s)
                at Properties.Method3() in C:UsersPaulDeitelDocumentsexamples
                   ch13Fig13_05PropertiesPropertiesProperties.cs:line 49
                --- End of inner exception stack trace ---
                at Properties.Method3() in C:UsersPaulDeitelDocumentsexamples
                   ch13Fig13_05PropertiesPropertiesProperties.cs:line 54
                at Properties.Method2() in C:UsersPaulDeitelDocumentsexamples
                   ch13Fig13_05PropertiesPropertiesProperties.cs:line 40
                at Properties.Method1() in C:UsersPaulDeitelDocumentsexamples
                   ch13Fig13_05PropertiesPropertiesProperties.cs:line 34
                at Properties.Main() in C:UsersPaulDeitelDocumentsexamples
                   ch13Fig13_05PropertiesPropertiesProperties.cs:line 14

             exceptionParameter.Message:
             Exception occurred in Method3

             exceptionParameter.StackTrace:
                at Properties.Method3() in C:UsersPaulDeitelDocumentsexamples
                   ch13Fig13_05PropertiesPropertiesProperties.cs:line 54
                at Properties.Method2() in C:UsersPaulDeitelDocumentsexamples
                   ch13Fig13_05PropertiesPropertiesProperties.cs:line 40
                at Properties.Method1() in C:UsersPaulDeitelDocumentsexamples
                   ch13Fig13_05PropertiesPropertiesProperties.cs:line 34
                at Properties.Main() in C:UsersPaulDeitelDocumentsexamples
                   ch13Fig13_05PropertiesPropertiesProperties.cs:line 14

             exceptionParameter.InnerException:
             System.FormatException: Input string was not in a correct format.
                at System.Number.StringToNumber(String str, NumberStyles options,
                    NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
                at System.Number.ParseInt32(String s, NumberStyles style,
                   NumberFormatInfo info)
                at System.Int32.Parse(String s)
                at Properties.Method3() in C:UsersPaulDeitelDocumentsexamples
                   ch13Fig13_05PropertiesPropertiesProperties.cs:line 49

Program execution begins with Main, which becomes the first method on the method-call stack. Line 14 of the try block in Main invokes Method1 (declared in lines 32–35), which becomes the second method on the stack. If Method1 throws an exception, the catch block in lines 16–28 handles the exception and outputs information about the exception that occurred. Line 34 of Method1 invokes Method2 (lines 38–41), which becomes the third method on the stack. Then line 40 of Method2 invokes Method3 (lines 44–57), which becomes the fourth method on the stack.

At this point, the method-call stack (from top to bottom) for the program is


                       Method3
                       Method2
                       Method1
                       Main

The method called most recently (Method3) appears at the top of the stack; the first method called (Main) appears at the bottom. The try statement (lines 47–56) in Method3 invokes method int.Parse (line 49), which attempts to convert a string to an int. At this point, int.Parse becomes the fifth and final method on the call stack.

13.7.4 Throwing an Exception with an InnerException

Because the argument to int.Parse is not in int format, line 49 throws a Format-Exception that’s caught in line 51 of Method3. The exception terminates the call to int.Parse, so the method is unwound (i.e., removed) from the method-call stack. The catch block in Method3 then creates and throws an Exception object. The first argument to the Exception constructor is the custom error message for our example, “Exception occurred in Method3.” The second argument is the InnerException—the Format-Exception that was caught. The StackTrace for this new exception object reflects the point at which the exception was thrown (lines 54–55). Now Method3 terminates, because the exception thrown in the catch block is not caught in the method body. Thus, control returns to the statement that invoked Method3 in the prior method in the call stack (Method2). This unwinds Method3 from the method-call stack.

When control returns to line 40 in Method2, the CLR determines that line 40 is not in a try block. Therefore the exception cannot be caught in Method2, and Method2 terminates. This unwinds Method2 from the call stack and returns control to line 34 in Method1.

Here again, line 34 is not in a try block, so Method1 cannot catch the exception. The method terminates and is unwound from the call stack, returning control to line 14 in Main, which is located in a try block. The try block in Main exits and the catch block (lines 16–28) catches the exception. The catch block uses properties Message, Stack-Trace and InnerException to create the output. Stack unwinding continues until a catch block catches the exception or the program terminates.

13.7.5 Displaying Information About the Exception

The first block of output (which we reformatted for readability) in Fig. 13.5 contains the exception’s string representation, which is returned from an implicit call to method To-String. The string begins with the name of the exception class followed by the Message property value. The next four items present the stack trace of the InnerException object.

The remainder of the block of output shows the StackTrace for the exception thrown in lines 54–55 of Method3. The StackTrace represents the state of the method-call stack at the throw point of the exception, rather than at the point where the exception eventually is caught. Each StackTrace line that begins with “at” represents a method on the call stack. These lines indicate the method in which the exception occurred, the file in which the method resides and the line number of the throw point in the file. The inner-exception information includes the inner-exception stack trace.

Error-Prevention Tip 13.5

When catching and rethrowing an exception, provide additional debugging information in the rethrown exception. To do so, create an object of an Exception subclass containing more specific debugging information, then pass the original caught exception to the new exception object’s constructor to initialize the InnerException property.

The next block of output (two lines) simply displays the Message property’s value (Exception occurred in Method3) of the exception thrown in Method3.

The third block of output displays the StackTrace property of the exception thrown in Method3. This StackTrace property contains the stack trace starting from line 54 in

Method3, because that’s the point at which the Exception object was created and thrown. The stack trace always begins from the exception’s throw point.

Finally, the last block of output displays the string representation of the Inner-Exception property, which includes the namespace and class name of the exception object, as well as its Message and StackTrace properties.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset