Exception Properties

As we discussed in Section 12.5, 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 error message associated with an Exception object. This message can be a default message associated with the exception type or a customized message passed to an Exception object's constructor when the Exception object is thrown. Property StackTrace 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.

Error Prevention Tip 12 5

A stack trace shows the complete method-call stack at the time an exception occurred. This enables the programmer to view the series of method calls that led to the exception. Information in the stack trace includes the names of the methods on the call stack at the time of the exception, the names of the classes in which the methods are defined and the names of the namespaces in which the classes are defined. If the program database (PDB) file that contains the debugging information for the method is available, 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. PDB files are created by the IDE to maintain the debugging information for your projects.

 

Property InnerException

Another property used frequently by class-library programmers is InnerException. Typically, class library programmers "wrap" exception objects caught in their code so that they then can throw new exception types that are specific to their libraries. For example, a programmer implementing an accounting system might have some 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 Convert.ToInt32, which throws a FormatException when it encounters an invalid number format. When an invalid account number format occurs, the accounting system 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 InvalidAccountNumberFormatException. In such cases, the programmer would provide code to catch the FormatException, then create an appropriate type of Exception object in the catch block and pass the original exception as one of the constructor arguments. The original exception object becomes the InnerException of the new exception object. When an InvalidAccountNumberFormatException occurs in code that uses the accounting system library, the catch block that catches the exception can obtain a reference to the original exception via property InnerException. Thus the exception indicates both that the user specified an invalid account number and that the problem was an invalid number format. If the InnerException property is null, this indicates that the exception was not caused by another exception.

Other Exception Properties

Class Exception provides other properties, including HelpLink, Source and TargetSite. Property HelpLink specifies the location of 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 application where the exception occurred. Property TargetSite specifies the method where the exception originated.

Demonstrating Exception Properties and Stack Unwinding

Our next example (Fig. 12.5) demonstrates properties Message, StackTrace and InnerException, and method ToString, of class Exception. In addition, the example introduces stack unwindingwhen 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 StackTrace and the stack-unwinding mechanism. To see the proper stack trace, you should execute this program using steps similar to those presented in Section 12.3.

Figure 12.5. Exception properties and stack unwinding.

(This item is displayed on pages 583 - 585 in the print version)

1 // Fig. 12.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 } // end try 16 catch ( Exception exceptionParameter ) 17 { 18 // output the string representation of the Exception, then output 19 // properties InnerException, Message and StackTrace 20 Console.WriteLine( "exceptionParameter.ToString: {0} ", 21 exceptionParameter.ToString() ); 22 Console.WriteLine( "exceptionParameter.Message: {0} ", 23 exceptionParameter.Message ); 24 Console.WriteLine( "exceptionParameter.StackTrace: {0} ", 25 exceptionParameter.StackTrace ); 26 Console.WriteLine( "exceptionParameter.InnerException: {0} ", 27 exceptionParameter.InnerException.ToString() ); 28 } // end catch 29 } // end method Main 30 31 // calls Method2 32 static void Method1() 33 { 34 Method2(); 35 } // end method Method1 36 37 // calls Method3 38 static void Method2() 39 { 40 Method3(); 41 } // end method Method2 42 43 // throws an Exception containing an InnerException 44 static void Method3() 45 { 46 // attempt to convert string to int 47 try 48 { 49 Convert.ToInt32( "Not an integer" ); 50 } // end try 51 catch ( FormatException formatExceptionParameter ) 52 { 53 // wrap FormatException in new Exception 54 throw new Exception( "Exception occurred in Method3", 55 formatExceptionParameter ); 56 } // end catch 57 } // end method Method3 58 } // end class Properties

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.Convert.ToInt32(String value) at Properties.Method3() in C:examplesch12Fig12_04Properties Properties.cs:line 49 --- End of inner exception stack trace --- at Properties.Method3() in C:examplesch12Fig12_04Properties Properties.cs:line 54 at Properties.Method2() in C:examplesch12Fig12_04Properties Properties.cs:line 40 at Properties.Method1() in C:examplesch12Fig12_04Properties Properties.cs:line 34 at Properties.Main() in C:examplesch12Fig12_04Properties Properties.cs:line 14 exceptionParameter.Message: Exception occurred in Method3 exceptionParameter.StackTrace: at Properties.Method3() in C:examplesch12Fig12_04Properties Properties.cs:line 54 at Properties.Method2() in C:examplesch12Fig12_04Properties Properties.cs:line 40 at Properties.Method1() in C:examplesch12Fig12_04Properties Properties.cs:line 34 at Properties.Main() in C:examplesch12Fig12_04Properties Properties.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.Convert.ToInt32(String value) at Properties.Method3() in C:examplesch12Fig12_04Properties Properties.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 3235), which becomes the second method on the stack. If Method1 throws an exception, the catch block in lines 1628 handles the exception and outputs information about the exception that occurred. Line 34 of Method1 invokes Method2 (lines 3841), which becomes the third method on the stack. Then line 40 of Method2 invokes Method3 (lines 4457), 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 4756) in Method3 invokes method Convert.ToInt32 (line 49), which attempts to convert a string to an int. At this point, Convert.ToInt32 becomes the fifth and final method on the call stack.

Throwing an Exception with an InnerException

Because the argument to Convert.ToInt32 is not in int format, line 49 throws a FormatException that is caught in line 51 of Method3. The exception terminates the call to Convert.ToInt32, so the method is removed (or unwound) 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 InnerExceptionthe FormatException that was caught. The StackTrace for this new exception object reflects the point at which the exception was thrown (lines 5455). 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 removes, or 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 28 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 expires and the catch block (lines 1628) catches the exception. The catch block uses method ToString and properties Message, StackTrace and InnerException to create the output. Note that stack unwinding continues until a catch block catches the exception or the program terminates.

Displaying Information About the Exception

The first block of output (which we reformatted for readability) in Fig. 12.5 contains the exception's string representation, which is returned from method ToString. 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 Method3. Note that 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. Note that the inner-exception information includes the inner exception stack trace.

Error Prevention Tip 12 6

When catching and rethrowing an exception, provide additional debugging information in the rethrown exception. To do so, create an Exception object 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. Note that this StackTrace property contains the stack trace starting from line 54 in Method3, because that is 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 InnerException property, which includes the namespace and class name of the exception object, as well as its Message and StackTrace properties.

Категории