Today I wrote a simple application, which shows what the difference is between initializing a static field in the explicit static constructor and doing the same during the declaration time (inline). I know that even when we initialize our static fields inline, the compiler will add an implicit static constructor to that class and initialize static values in that method. But this example showed me that there is really a long time difference between initializing static fields inline and in explicit static constructor. Here are a screenshot from the example – in this example BeforeFieldInit means that the static fields are initialized inline and NotBeforeFieldInit means that static fields are initialized in the explicit static constructor:


Declaring a static field and initializing its value in an explicit static constructor.

using System;
namespace BeforeFieldInitExample
{
    public class NotBeforeFieldInit
    {
        // here there is only decleration of the static field
        public static int A;

        static NotBeforeFieldInit()
        {
            // Initialization of A's values is here in the explicit static constructor
            A = 0;
        }
    }
}

Initializing a static fields value during the decleration (inline).

using System;
namespace BeforeFieldInitExample
{
    public class BeforeFieldInit
    {
        public static int A = 0;
    }
}

These two code groups will work as the same and produce the same result. Actually when we compile the second code, the output will be as the same with the first code. I mean, during the compiling time the compiler will create an implicit static constructor for the BeforeFieldInit class and initialize the field’s value in that method. So it will be the same with the first code.

But there is a small difference between these codes. The difference can only be seen by checking the IL codes of these types.

For the first example, IL code of the class NotBeforeFieldInit will be as follows:

class public auto ansi NotBeforeFieldInitClass
            extends object
{
    .method public hidebysig specialname 
            rtspecialname instance 
            void .ctor() cil managed
    {
        // Code Size: 7 byte(s)
        .maxstack 8
        L_0000: ldarg.0 
        L_0001: call instance void object::.ctor()
        L_0006: ret 
    }

    .method private hidebysig specialname 
            rtspecialname static 
            void .cctor() cil managed
    {
        // Code Size: 22 byte(s)
        .maxstack 8
        L_0000: nop 
        L_0001: ldc.i4.0 
        L_0002: stsfld int32 BeforeFieldInitExample.NotBeforeFieldInitClass::A
        L_0007: ldc.r8 9
        L_0010: stsfld float64 BeforeFieldInitExample.NotBeforeFieldInitClass::B
        L_0015: ret 
    }

    .field public static int32 A
    .field public static float64 B
}

And for the second example, which the name of the class is BeforeFieldInit’s IL code will be as runs:

class public auto ansi 
            beforefieldinit // here beforefieldinit mask is added
                BeforeFieldInitClass
        extends object
{
    .method public hidebysig specialname 
            rtspecialname instance 
            void .ctor() cil managed
    {
       // Code Size: 7 byte(s)
        .maxstack 8
        L_0000: ldarg.0 
        L_0001: call instance void object::.ctor()
        L_0006: ret 
    }

    .method private hidebysig specialname 
            rtspecialname static 
            void .cctor() cil managed
    {
        // Code Size: 21 byte(s)
        .maxstack 8
        L_0000: ldc.i4.0 
        L_0001: stsfld int32 BeforeFieldInitExample.BeforeFieldInitClass::A
        L_0006: ldc.r8 9
        L_000f: stsfld float64 BeforeFieldInitExample.BeforeFieldInitClass::B
        L_0014: ret 
     }    
     .field public static int32 A
     .field public static float64 B
}

IL codes generated by Xenocode Fox 2007

As you see in the IL the only difference between these two codes is the second class’s having the beforefieldinit flag. So what is this flag doing?

beforefieldinit flag tells to the JIT that this class’s static fields are initialized inline. If a class has no beforefieldinit flag, then JIT compiler will automatically check whether explicit static constructor is called before. This means that whenever you want to try to access any static member of this class or try to create a new instance of this class, JIT will automatically calls the explicit static constructor. Therefore you will loose performance because whenever you try to access a static member, JIT also checks whether static constructor is invoked before. But in the second example if we add a beforefieldinit flag to our class, this means that our static members are initialized inline, so JIT does not need to check whether static constructor is invoked before. This is the main reason that causes performance difference between those two classes. When we wrote an explicit static constructor and initialize our fields’ values, the compiler will not add beforefieldinit flag to that class. But if we initialize our static fields inline, then compiler will add an implicit static constructor and initialize our static fields there and also add the beforefieldinit flag to our class.

So always, try to use inline field initialization for the static fields if you can.

Share: