Search code examples
c#c++.netinitializationinitialization-order

Ambiguity in initialization order of static variables


During my research into the best way to build a Singleton in C# I stumbled across the following article where there is a brief mention that in C++

"The C++ specification left some ambiguity around the initialization order of static variables."

I ended up looking into the question and found this and this. Where basically the point (as far as I understand) is that the initialization order of static variables in C++ is undefined. Ok I guess so far so good, but then I wanted to understand the following statement that the article later makes

"Fortunately, the .NET Framework resolves this ambiguity through its handling of variable initialization."

So I found this page where they say

The static field variable initializers of a class correspond to a sequence of assignments that are executed in the textual order in which they appear in the class declaration.

and give the example of

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");
}

the output must be: 
Init B 
Init A
1 1

"Because the rules for when static constructors execute (as defined in Section 10.11) provide that B's static constructor (and hence B's static field initializers) must run before A's static constructor and field initializers."

But where I am confused is that my understanding was that the initialization order of static variables in these examples would be based on when a method or field within the class was first invoked, which is in turn based on the execution order of the block of code (this case left to right). IE: Completely independent of where - or the order - of the class declaration. Yet by my interpretation of that article it says its as a result of the order of declaration of those classes, which my testing doesn't back up?

Could someone please clarify this (and the point the article is trying to make) for me and perhaps provide a better example that illiterates the behaviour described?


Solution

  • The static field variable initializers of a class correspond to a sequence of assignments that are executed in the textual order in which they appear in the class declaration.

    This means that within the same class, static fields are initialized in order of appearance in the source code. For example:

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

    When it's time for the static fields to be initialized, X is guaranteed to be initialized before Y.

    "Because the rules for when static constructors execute (as defined in Section 10.11) provide that B's static constructor (and hence B's static field initializers) must run before A's static constructor and field initializers."

    This means that the static constructor and member initialization for each class will run in evaluation order when expressions that access these classes appear¹. The relative order of appearance of the class definitions in source code does not play any role, even if they appear in the same source file (which they most certainly are not obliged to do). For example:

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

    Assuming that neither A nor B has already been statically initialized, order of evaluation guarantees that all the fields of B will be initialized before any field of A. The fields of each class will be initialized in the order specified by the first rule.


    ¹ for the purposes of this discussion I am ignoring the existence of beforefieldinit.