Recipe7.16.Preventing the Nefarious TypeInitializationException


Recipe 7.16. Preventing the Nefarious TypeInitializationException

Problem

Problems can occur when initializing a class's or a structure's static fields. Some of these problems are serious enough to raise a TypeInitializationException exception. Unfortunately, this exception can be hard to track down and can potentially shut down your application. You want to prevent this from occurring.

Solution

To demonstrate how to handle a TypeInitializationException, take the following example that initializes static fields to a value, null, or does not initialize them at all (not initializing is not recommended, of course), as is the case with the following class:

 public class TestInit {     public static object one;     public static string two = one.ToString( ); } 

You should consider rewriting the class to include a static constructor that performs the initialization of the static fields. This will aid in the debugging of your static fields:

 public class TestInit {     static TestInit( )     {         try         {             one = null;             two = one.ToString( );         }         catch (Exception e)         {             Console.WriteLine("CAUGHT EXCEPTION IN .CCTOR: " + e.ToString( ));         }     }          public static object one;     public static string two; } 

Discussion

To see this exception in action, run the following method:

 public static void Main( ) {     // Causes TypeInitializationException     TestInit c = new TestInit( );     // Replacing this method's code with the following line     // will produce similar results.     //TestInit.one.ToString( ); } 

This code creates an instance of the TestInit class. You are assured that any static fields of the class will be initialized before this class is created, and any static constructors on the TestInit class will be called as well. The TestInit class is written as follows:

 public class TestInit {     public static object one = null;     public static string two = one.ToString( ); } 

As you can see, a NullReferenceException should be thrown on the second static field, since it is trying to call ToString on an object set to null. If run from the development environment, you will see the exception dialog pop up. The exception dialog shown is depicted in Figure 7-4. The application is blocked until shut down manually through the IDE.

Figure 7-4. An unhandled TypeInitializationException dialog


However, if this executable is run from outside the development environment, the message box shown in Figure 7-5 is displayed and the application can either be shut down or debugged.

Figure 7-5. An unhandled runtime exception


Now, let's wrap a try-catch block around the Main method, as shown here:

 public static void Main( ) {     try     {         // Causes TypeInitializationException         TestInit c = new TestInit( );     }     catch(Exception e)     {         Console.WriteLine("CAUGHT EXCEPTION IN CREATING METHOD: " + e.ToString( ));     } } 

When this code is run inside the development environment, the TypeInitializationException is caught by the new exception handler that you added to the Main method. The text displayed by the exception handler is shown here:

 CAUGHT EXCEPTION IN CREATING METHOD: System.TypeInitializationException: The type initializer for 'TestInit' threw an exception. ---> System.NullReferenceException: Object reference not set to an instance of an object.    at CSharpRecipes.ExceptionHandling.TestInit..cctor() in C:\Book_2_0\Code\ CSharpRecipes\07_ExceptionHandling.cs:line 729    --- End of inner exception stack trace ---    at CSharpRecipes.ExceptionHandling.TestInit..ctor()    at CSharpRecipes.ExceptionHandling.TestTypeInitFailure() in C:\ \Book_2_0\Code\ CSharpRecipes\07_ExceptionHandling.cs:line 708 

The TypeInitializationException wraps the NullReferenceException that was the original exception thrown. The runtime provides the TypeInitializationException wrapper automatically.

A third method of trapping this exception is to use the exception event handler. This exception event handler is described in detail in Recipe 7.10. When only this exception handler is employed with no supporting try-catch or try-catch-finally blocks, the following events occur when running the executable in the development environment:

  1. The exception dialog shown in Figure 7-4 is displayed.

  2. The event exception handler intercepts the exception before the application is terminated. When the executable is run standalone, the message box in Figure 7-5 is displayed first. Then, the event exception handler intercepts the exception, and, finally, the application is terminated.

The second method seems to work best; use TRy-catch blocks at a minimum around code that will potentially cause static fields to initialize.

There is a way to eliminate the TypeInitializationException from the picture. You can simply initialize your class's or structure's static fields within the appropriate static constructor(s), first presented in the Solution section of this recipe and shown again here:

 public class TestInit {          static TestInit( )     {         try         {             one = null;             two = one.ToString( );         }         catch (Exception e)         {             Console.WriteLine("CAUGHT EXCEPTION IN .CCTOR: " + e.ToString( ));         }     }     public static object one;     public static string two; } 

When this code is executed, the catch block captures the real exception and there is no fear of the application shutting down. The text displayed by the catch block is as follows:

 CAUGHT EXCEPTION IN .CCTOR: System.NullReferenceException: Object reference not set to an instance of an object.    at Chapter_Code.TestInit..cctor( ) in c:\book cs cookbook\code\test.cs:line 191 

This is much cleaner and more elegant than the other solutions. In addition, tracking down the source of the bug is much easier. As a note, this exception now operates in the same manner regardless of whether the application is being run in the development environment.

See Also

See the "Error Raising and Handling Guidelines" and "TypeInitializationException Class" topics in the MSDN documentation.



C# Cookbook
Secure Programming Cookbook for C and C++: Recipes for Cryptography, Authentication, Input Validation & More
ISBN: 0596003943
EAN: 2147483647
Year: 2004
Pages: 424

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net