Problems can occur when
initializing a class 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.
If you are initializing static fields to a value, null, or not initializing them at all, 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; }
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. We 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 two message boxes pop up in sequence. The first is the
message box depicted in Figure 5-4. The second
message box shown is depicted in Figure 5-5. The
application proceeds to shut down at this point.
However, if this executable is run from outside the development environment, the message box shown in Figure 5-6 is displayed and the application shuts down.
Now, let’s add 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 message
box in Figure 5-4 appears again, but the
TypeInitializationException
is caught by the new
exception handler that we 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 Chapter_Code.TestInit..cctor( ) in c:ook cs cookbookcode est.cs:line 200 --- End of inner exception stack trace --- at Chapter_Code.TestInit..ctor( ) at Chapter_Code.Class1.TypeinitExceptionPrevention( ) in c:ook cs cookbook code est.cs:line 175
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 5.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:
The message boxes shown in Figures Figure 5-4 and Figure 5-5 are displayed in that order.
The event exception handler intercepts the exception before the application is terminated. When the executable is run standalone, the message box in Figure 5-6 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. We can simply initialize our class or
structure’s static fields within the appropriate
static constructor(s), shown in the Solution section of this recipe.
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:ook cs cookbookcode est.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.