Static Constructor throws the same exception again and again
Here’s a little gotcha I ran into today – if you have code in a class’s static constructor that throws an exception, we will get a TypeInitializationException with the original exception as the InnerException – so far, nothing new.
However, if we keep on calling methods on that object, we’ll keep receiving TypeInitializationExceptions. If it cannot be initialized, it cannot be called. Every time we try, we’ll receive the exact same exception. However, the static ctor will not be called again. What appears to happen is that the CLR caches the TypeInitializationException object itself, InnerException included, and rethrows it whenever the type is called.
What are the ramifications? Well, we received an OutOfMemoryException in our static ctor, but the outer exception was caught and tried again. So we got an OutOfMemoryException again, even though the memory problem was behind us, which sent us down the wrong track of looking for persistent memory problems. Theoretically, it could also be a leak – the inner exception holding some sort of reference that is never released, but that’s an edge case.
Here’s some code to illustrate the problem. The output clearly shows that while we wait a second between calls, the inner exception contains the time of the original exception, not any subsequent calls. Debugging also shows that the static ctor is called only once.
1: class Program
2: {
3: static void Main(string[] args)
4: {
5:
6: for (int i = 0; i < 5; i++)
7: {
8: try
9: {
10: Thread.Sleep(1000);
11: StaticClass.Method();
12:
13: }
14: catch (Exception ex)
15: {
16: Console.WriteLine(ex.InnerException.Message);
17: }
18: }
19:
20: Console.ReadLine();
21: }
22: }
23:
24: static class StaticClass
25: {
26: static StaticClass()
27: {
28: throw new Exception("Exception thrown at " + DateTime.Now.ToString());
29: }
30:
31: public static void Method()
32: { }
33:
34: }
5 Comments
Comments have been disabled for this content.
AndrewSeven said
I can't find the official doc, but I've always believed that a static initialization exception rendered they type unusable for the life of the app domain.
Avner Kashtan said
It does, if by "unusable" you mean "throws a TypeInitializationException for the life of the app domain" and by "throws a TypeInitializationException" you mean "throws THE SAME TypeInitializationException instance". :)
Visual Guard for Sybase ASE said
Even I think they are unusable for the rest of the life of app domain.
Mary said
Yeah, it happens sometimes ... Nothing special.
Amanda said
Yeah, it happens sometimes ... Nothing special.