Robert Chipperfield

Say hello, static constructor?

Published Friday, August 03, 2007 11:12 AM

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:
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:
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!

Comments

 

Thomas Danecker said:

- "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."

There is no inheritance of static methods! It's a feature of C# to be able to use Sub.SayHello instead of Super.SayHello. In sense of IL, Sub.SayHello doesn't exist.

There are quite more impacts of type-initializer than you may think of. According to Jeffrey Richter's book "CLR via C#": At JIT-compile-time, the JIT compiler checks if the type was already initialized. If not, it injects the type initialization directly into the generated native code. So if you are accessing a typ with an type initializer in a tight loop first, you may expect have performance degradations (in Jeffrey's (extreme) example, the loop needed > 300% more time - 7 seconds instead of 2). This behaviour can be relaxed with the BeforeFildInit flag wich is set by the C# compiler if the static fields are inizialized inline and no explicit static constructor is present.
August 6, 2007 1:35 AM
 

RobertChipperfield said:

Hi Thomas,

I know there's no inheritance of static methods, but the fact the syntax (in C# at least) lets you do it is a little misleading in my opinion...

With regards to the performance impact of type initializers, I'd heard about the CLR checks to see whether it'd been run or not, though I didn't realise these were put in or otherwise at JIT time - that's interesting to know.

Cheers,
Rob
August 6, 2007 2:24 AM
You need to sign in to comment on this blog

About RobertChipperfield

I'm a software engineer at Red Gate, where I've worked since September 2006. I've worked on a wide range of products, including Exchange Server Archiver, SQL Data Compare, SQL Log Rescue, SQL Multi Script, SQL Doc, and ANTS Profiler.

Outside of work, I enjoy amateur radio, electronics, and of course the usual assortment of computer-related technologies, from hardware all the way through to high-level software.



















<August 2007>
SuMoTuWeThFrSa
2930311234
567891011
12131415161718
19202122232425
2627282930311
2345678
Microsoft Office Communications Server 2007 R2 – Part II
  Once you have set up Office Communication Server 2007 R2 to provide IM within the rganisation, the... Read more...

Mission Critical: Database Design
 There is nothing like a checklist to make sure you've completed all the tasks in designing a database,... Read more...

SQL Server Intellisense VS. Red Gate SQL Prompt
 Fabiano Amorim is hooked on today's Integrated Development Environments with built-in Intellisense, so... Read more...

Doug Crockford: Geek of the Week
  Doug Crockford is the man behind JavaScript Object Notation (JSON). He is a well-known critic of XML... Read more...

Raw Materials: Mirror, Mirror, on the Desk
 Seeing ourselves as we see ourselves. Read more...