When does the static constructor of your .NET class actually get called?
Sounds like it should be pretty obvious really – at least going on the side of “how late can it possibly be called”. Most of us are used to the idea that static constructors are called before any other methods on that class are called. I know I hadn’t given it too much more thought than that.
According to the MSDN page on static constructors, they will be “…called automatically to initialize the class before the first instance is created or any static members are referenced”.
However, what I didn’t realise is the implications this had when you start calling static methods on subclasses of your types. Consider the following code:
1 |
static class Program{ static void Main() { Sub.SayHello(); Sub.NoOp(); Sub.SayHello(); Console.ReadLine(); }}class Super{ protected static string m_String = ""; static Super() { Console.WriteLine("Super..cctor() called"); } public static void SayHello() { Console.WriteLine(m_String); }}class Sub : Super{ static Sub() { Console.WriteLine("Sub..cctor() called"); m_String = "Hello world!"; } public static void NoOp() { }} |
Now, if you run that, I would have expected to see something along the lines of:
Super..cctor() called
Sub..cctor() called
Hello world!
Hello world!
But no! What you actually get is:
Super..cctor() called
<Not set yet>
Sub..cctor() called
Hello world!
In other words, calling a static method on a subclass that is defined on the superclass does not cause the subclass’s static constructor to execute! Only when the first member of the subclass is accessed is the static constructor called.
Now, the interesting thing is that if you look at it in Reflector, you’ll see that the compiler has actually called Super.SayHello() rather than Sub.SayHello() as in the original source:
1 |
private static void Main(){ Super.SayHello(); Sub.NoOp(); Super.SayHello(); Console.ReadLine();} |
I guess this is a performance win, since the inheritance hierarchy can be traversed at compile-time rather than design-time, but I’m a bit sceptical. Does this really honour the contract that the static constructor will be called before “any static members are referenced”? Let me know what you think!
Load comments