Search code examples
c#c#-3.0c#-2.0initializerstatic-constructor

static readonly field initializer vs static constructor initialization


Below are two different ways to initialize static readonly fields. Is there a difference between the two approaches? If yes, when should one be preferred over the other?

class A
{
    private static readonly string connectionString =
        WebConfigurationManager.ConnectionStrings["SomeConnection"].ConnectionString;
}

class B
{
    private static readonly string connectionString;

    static B()
    {
        connectionString =
            WebConfigurationManager.ConnectionStrings["SomeConnection"].ConnectionString;
    }
}

Solution

  • There is one subtle difference between these two, which can be seen in the IL code - putting an explicit static constructor tells the C# compiler not to mark the type as beforefieldinit. The beforefieldinit affects when the type initializer is run and knowing about this is useful when writing lazy singletons in C#, for example.

    In brief the difference is this:

    .class private auto ansi beforefieldinit A
    .class private auto ansi B
    

    In all other aspects they are the same. Output from Reflector:

    Class A:

    .class private auto ansi beforefieldinit A
        extends [mscorlib]System.Object
    {
        .method private hidebysig specialname rtspecialname static void .cctor() cil managed
        {
            .maxstack 8
            L_0000: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string, class Connection> WebConfigurationManager::ConnectionStrings
            L_0005: ldstr "SomeConnection"
            L_000a: callvirt instance !1 [mscorlib]System.Collections.Generic.Dictionary`2<string, class Connection>::get_Item(!0)
            L_000f: ldfld string Connection::ConnectionString
            L_0014: stsfld string A::connectionString
            L_0019: ret 
        }
    
        .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
        {
            .maxstack 8
            L_0000: ldarg.0 
            L_0001: call instance void [mscorlib]System.Object::.ctor()
            L_0006: ret 
        }
    
        .field private static initonly string connectionString
    } 
    

    Class B:

    .class private auto ansi B
        extends [mscorlib]System.Object
    {
        .method private hidebysig specialname rtspecialname static void .cctor() cil managed
        {
            .maxstack 8
            L_0000: nop 
            L_0001: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string, class Connection> WebConfigurationManager::ConnectionStrings
            L_0006: ldstr "SomeConnection"
            L_000b: callvirt instance !1 [mscorlib]System.Collections.Generic.Dictionary`2<string, class Connection>::get_Item(!0)
            L_0010: ldfld string Connection::ConnectionString
            L_0015: stsfld string B::connectionString
            L_001a: ret 
    }
    
        .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
        {
            .maxstack 8
            L_0000: ldarg.0 
            L_0001: call instance void [mscorlib]System.Object::.ctor()
            L_0006: ret 
        }
    
    
        .field private static initonly string connectionString    
    }