Search code examples
c#staticstatic-constructor

static field initialization explanation and its requirement


After looking at so many complicated questions related to this i want to ask the explanation for following code having static field initialization. one more thing i want to know is the requirement of static field initialization. In which scenarios it ll be helpful??

using System;

class Test
{
    static void Main()
    {
        Console.WriteLine("{0} {1}", B.Y, A.X);
    }

    public static int F(string s)
    {
        Console.WriteLine(s);
        return 1;
    }
}

class A
{
    static A()
    { }

    public static int X = Test.F("Init A");
}

class B
{
    static B()
    { }

    public static int Y = Test.F("Init B");
}

Output:

Init B

Init A

1 1

When no static constructor is present then output may vary. I am not able to understand the rationale behind it.What difference static field initialization has brought to this fragment?. Can someone please help. I am a newb with c#.


Solution

  • When a type has a static constructor, the runtime is constrained to execute all type initialization immediately before the first use of any member of the type.

    When it doesn't have a static constructor, the runtime has much more freedom - it has to execute the type initializer at some point before the first use of a static field or before an instance is constructed, but that's all. You can even observe static methods which don't touch static fields being executed without the type initializer executing.

    In your case, both A and B have static constructors, and the order of access to the members is B first, then A, hence your output. Without those static constructors, you'd still be guaranteed to get "1 1" as the last line, and you'd still get both "Init A" and "Init B", but the ordering of them wouldn't be guaranteed.

    This is just the way the language and runtime are specified - and usually it has no impact, as usually type initializers should just be setting up the type, with no other side effects. Type initializers should do as little as possible, ideally - if they fail for some reason, the type will never be usable; type initializers aren't retried.

    For more details, see my beforefieldinit article and .NET 4.0 type initializer changes blog post.