Question

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?

Was it helpful?

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.

OTHER TIPS

In C++ the order of initialization of variables with static storage duration in a single translation unit is the order in which the definitions of such variables occur. It is unspecified what the order of initialization of variables with static storage duration is across different translation units.

That is, the C++ standard does offer a similar guarantee to what you quoted, substituting the order of declaration in the class for the order of definition in the single translation unit that defines such variables. But that is not the important difference.

While in C++ that is the only guarantee, in C# there is the added guarantee that all static members will be initialized before the first use of the class. This means that, if your program depends on A (consider each type in a different assembly which is the worst case), it will start the initialization of all static fields in A, if A in turn depends on B for any of those static initializations, then the initialization of B static members will be triggered there.

Contrast that with C++, where during static initialization[*], all other variables with static duration are assumed to be initialized. This is the main difference: C++ assumes that they are initialized, C# ensures that they are before that use.


[*] Technically the case where this is problematic could be dynamic initialization in the standard. Initialization of variables with static storage duration inside a each translation unit is a two step process, where during the first pass static initialization sets the variables to a fixed constant expression, and later in a second pass called dynamic initialization all variables with static storage whose initializer is not a constant expression are initialized.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top