LA.NET [EN]

Jul 15

Back to the basics: type constructors

Posted in Basics      Comments Off on Back to the basics: type constructors

After the last two posts, I guess you could see this coming, right? Today it’s all about type constructors (and it’s a long post, so make sure you’re comfy). What is a type constructor (aka, class constructor)? In C#, it’s a static and private parameterless method which is named after the class where it’s defined. Here’s a small example:

class MyClass {
    static MyClass() {
        //initialize static fields here
    }
}

Type constructors must be private (in fact, in C# you can’t even use  that qualifier or the compiler will start complaining) and can’t receive any arguments. In practice, this means that you can only have one type constructor. Typically, you’ll be using type constructors to initialize static fields. Here’s an example:

class MyClass {
    private static Int32 _myField;
    static MyClass() {
        _myField = 10;
    }
}

If you’re just initializing static fields with “simple” expressions, then you can use the same technique I’ve shown you before for instance constructors. In other words, you can use static field initialization:

class MyClass {
    private static Int32 _myField = 10;
}

When the previous class is compiled, you’ll end up with code that is identical to the first snippet. To be sure,you can always fire up Reflector and see what’s the generated C#:

reflector

The previous image shows another interesting thing: type constructors are always named .cctor in the metadata table which contains the methods definitions of a type. Notice  that the C# compiler will never generate a type constructor automatically when the class doesn’t have any static fields which use the initialization “trick” I’ve mentioned above. Another interesting caveat is that type constructors don’t call the base type constructor (if it exists,that is). Here’s some  code that shows this:

class Program {
    static void Main(string[] args) {
        Console.WriteLine(MyDerived.SomeField);
    }
    class MyClass {
        static MyClass(){
            Console.WriteLine("MyClass");
        }
    }
    class MyDerived:MyClass{
        public static Int32 SomeField = 10;
        static MyDerived()  {
            Console.WriteLine("Derived");
        }
    }
}

When I first notice this, I was  a little bit surprised since that “seems” to go against what’s expected. Anyway, it works this way and that’s that. I was also surprised the first time I got a TypeInitializationException when trying to instantiate a new variable of a specific type. After some debugging, I’ve noticed that my type constructor was generating an exception which was being silently caught (poor coding, I know) before I tried to instantiate an object of that type. What I’m trying to say is that if your type constructor throws, then you can no longer instantiate an instance of that type in the current AppDomain.

Type constructors do have more surprises…Type constructor invocation is injected on the fly by the JIT when it detects that a “piece” of code is trying to access a type which has a static constructor that hasn’t been invoked yet. Since the CLR guarantees that a static constructor is executed only once (per AppDomain), then the thread that calls it does it from within a lock. Even if there are multiple threads trying to execute the constructor, only one will be able to call the type constructors while the others wait for the lock.

When the lock is released, they will notice that the type constructor has already been invoked and won’t call them again. Things can get a little complicated when you have two static constructors of different classes that “reference” each other. Interestingly, the CLR does ensure that both static constructors are called, but it can’t guarantee that one type constructor is run to completion before the other is executed.

But there’s more! As I’ve said, the JIT needs to decide where to insert the static constructor call when it notices that some piece of code is trying to access a member of a type which defines a static constructor. This makes sense, but it was only after reading Jeffrey Richter’s fantastic book that I’ve managed to get a clear picture of what’s happening. 

The static constructor call can be made *immediately* before some piece of code that creates an instance of that type or accesses a member of the type. Another option is to  guarantee that the call will be made *sometime* before one of those things happen. These two strategies are known as precise semantics and before-field-init semantics (respectively). Even though the CLR supports both approaches, the before-field-init semantics is the preferred option since it lets the CLR decide when to make the static constructor call (and this can bring huge gains in performance).

In practice, the approach used is defined by the compiler. When the C# compiler sees that you’ve explicitly defined a type constructor, it will always use the precise semantics call. If you’re just using inline initilization (and have no static constructor), then the compiler will use the before-field-init semantics. Notice that this information is maintained in the metadata table of a type (there’s a flag called beforefieldinit which is signaled for the before-field-init semantics).

And that’s it for today. Stay tuned for more.