Field Initialization Subtleties

If you've been programming in C# for a while you're probably already familar with variable initializers. When variables in your class or struct require initial values, it's common to assign these values using variable initializers rather than assigning them within instance or static constructors. Variable initializers allow us to assign initial values to variables at the point where they're declared. The listing below shows a simple example of a class that uses static and instance initializers:

class Test {
	// Two static initializers.
	static decimal startingBalance = 2500;
	static String startingLocation = "TADCASTER";

	// An instance initializer.
	int daysUntilExpiration = 64;

	// More code here...
}

On the surface, variable initializers are pretty simple. There are, however, some subtlties in dealing with static variable initialization that can trip you up and make you wonder why your code has turned against you.

Before discussing variable initializers further we have to be on the same page in terms of what we're talking about in this article. We're going to look at the sublties surrounding the initialization of static and instance variables only (collectively, it's common to refer to these variables as, fields). Specifically, we won't consider local variables or parameters to methods. I'm going to assume you know the difference between static and instance variables and what instance and static constructors are.

A few times I will quote from The C# Language Specification, v5.0. From this point onward I'll simply refer to this as, "The C# Specification". I'll often mention characteristics of a class. For example, I'll might say, "the CLR will run a class' static initializers prior to the first reference to a static field in the class." Even though I say, "class", it should be understood that I'm referring to structs as well. I just won't bother saying, "classes and structs". Finally, understand that whenever I say, "the CLR", I'm referring to the .NET Runtime Execution Environment.


A Simple First Example


Let's take a look at a simple variable initializer example to get started. See if you can predict what output the following code listing will produce, or if it will even compile for that matter. Field initializers execute in the order in which they are declared in the containing class so in the example below, the variables will be initilaized in the order a, b, r, t.

class Test {
	static int a = b + 1;
	static int b = a + 1;

	int r = 1;
	int t = r + 1;

	static void Main() {
		Test test = new Test();
		Console.WriteLine("a={0}, b={1}, test.r={2}, test.t={3}", a, b, test.r, test.t);
	}
}

You might see a problem on lines 2 and 3: The variable, a, is assigned a value based on b, which has not yet been initilized. Actually, this is not a problem for static variables in the same class (it becomes more interesting when a and b are in separate classes, as we'll see). All fields in a C# program (regardless of whether they're static or instance) are first initialized by the CLR to a default value appropriate to the type of the variable. (You can see these default values here.) This default value assignment occurs before and is independent of variable initializers specified by the programmer. In the above example, this means that both a and b will be initialized by the CLR to zero (the default value for all int types) prior to any assignments specified by the programmer. As a result, variable, a, will be assigned a value of 1 (since b is zero at the point where a is initialized) and b will be assigned a value of 2.

We're not out of the woods yet — what about the assignments to variables r and t on lines 5 and 6? Don't these variables also get assigned the default values for the int type? Yes, they do, or rather, they would, except that this code does not compile. The problem is with line 6. According to §10.5.5.2 of The C# Specification, "A variable initializer for an instance field cannot reference the instance being created." That's a fancy way of saying a variable initializer cannot make use of the this keyword. Even though line 6 does not explicitly use the this keyword, its use is implied. Line 6 is exactly equivalent to:

int t = this.r + 1;

and as The C# Specification says, this is not allowed.

If we really need to assign variable t as shown above, we'd have to move the assignment to a constructor like this:

Test() {
	t = r + 1;
} // c'tor Test()

Static Initializer Subtleties


We're going to look now at the subtleties in working with static initializers. I want you to keep in mind a couple important quotes from The C# Specification as you look at the next few code snippets. Section 10.5.5.1 of The C# Specification says:

If a static constructor (§10.12) exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor. Otherwise, the static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class.

From the piece highlighted in yellow, we know that in the absence of a static constructor, the CLR is free to run static initializers when it sees fit, so long as a class' static initializers are run prior to the first use of a field from the containing class. This passage gives the CLR the freedom to run static initializers from one class before those of another. Although not mandated by the C# Specification, we'll see that when the CLR begins executing static initializers for a given class it will usually execute all the static intializers for the class before executing static initiaizers for another class. I say, usually for the obvious reason — there is an exception we'll be discussing this later.

According to the piece highlighted in green, if a static constructor is present, the static initializers run immediately prior to the static constructor. So we have to ask, "When does the static constructor run?" For this, we turn to §10.12 of The C# Specification:

The execution of a static constructor is triggered by the first of the following events to occur within an application domain:

Since the code I'm about to show you has no static constructors, only the second (yellow highlighted) sentence from the above passage is relevant for now. Let me emphasize once again how the CLR can executute static initializers in classes that do not have static constructors. The following summary box will take you a long way in understanding the CLR view of static initializers.

For Classes Without Static Constructors

For classes without static constructors the CLR is free to execute the class' static initializers when it it sees fit (or even not at all, if no static fields from the class are ever used) so long as the static initialziers complete execution prior to the first reference to a static field in the class. Note in particular:

  1. Given two or more classes, no determination can be made as to the order in which the classes will be selected to have their static initializers executed, or even if a particular class' static initialziers will execute.
  2. There is no guarantee that a class' static initialziers will execute simply because a static method in the class is referenced.
  3. There is no guarantee that a class' static initialziers will not execute under any particular circumstance.

When a static constructor is present things are a bit different and, you'll be relieved to know, simpler.

We'll look later at how things change when static constructors are present but for now, have a look at the code below, keeping in mind the second sentence from §10.5.5.1. Notice that both classes A and B have static constructors that are presently commented out.

using System;

class Test {
	static void Main() {
		Console.WriteLine("After, A.X={0} B.Y={1}", A.X, B.Y);
	}
	public static int PrintMessage(string message) {
		Console.WriteLine(message);
		return 999;
	}
} // class Test

class A {
	// static A() {}
	public static int _m = Test.PrintMessage("Init A._m");
	public static int _p = Test.PrintMessage("Init A._p");

	public static int X {
		get {
			Console.WriteLine("In A.X getter");
			return _m;
		}
	}
} // Class A

class B {
	// static B() {}
	public static int _r = Test.PrintMessage("Init B._r");
	public static int _t = Test.PrintMessage("Init B._t");

	public static int Y {
		get {
			Console.WriteLine("In B.Y getter");
			return _t;
		}
	}
} // class B

Below is the output I get when running this program, but this reflects just one case of how the CLR might decide to execute the static initializers.

Init A._m
Init A._p
In A.X getter
Init B._r
Init B._t
In B.Y getter
After, A.X=999 B.Y=999

From the above output we see the CLR decided to run the static initialzers for class A before those for class B, but it didn't have to be this way. Remember the CLR can decide when to run a class' static initialziers. We could just as well have seen the following output:

Init B._r
Init B._t
Init A._m
Init A._p
In A.X getter
In B.Y getter
After, A.X=999 B.Y=999

Another example of potential output is this:

Init A._m
Init A._p
Init B._r
Init B._t
In A.X getter
In B.Y getter
After, A.X=999 B.Y=999

Technically, even of the following outputs is possible:

In A.X getter
Init A._m
Init A._p
In B.Y getter
Init B._r
Init B._t
After, A.X=999 B.Y=999

In the last case the static initializers for the classes were not executed until the static fields, A._x and B._y were referenced from within their respective class' "getter" methods. Although exceedingly unlikely and thoroughly unexpected, even the following output would theoretically be possible without violating the The C# Specifciation:

In A.X getter
Init B._r
Init B._y
Init A._u
Init A._x
In B.Y getter
After, A.X=999 B.Y=999

As an aside, if you're wondering why the line, "In A.X getter" always appears before "In B.Y getter" in all five outputs it's because A.X and B.Y were passed as parameters to Console.WriteLine() and parameters to methods are always evaluated left to right. There's a subtlety to be noted here: Do not make the mistake of thinking that class A's static initialziers were executed before those of class B simply because A.X appeared before B.Y as a parameter to Console.WriteLine(). This is not the case. Recall from the second sentence of §10.5.5.1 of The C# Specification, that in the absence of static constructors, "static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class." The fact that "In A.X getter" appeared in the output before "In B.Y getter" is a due to the fact that method parameters are evaluated left to right and therefore, the get accessor for class A was invoked before that of class B. This does not imply the static initializers for A must execute prior to those of class B.

Next, we'll look at how the above output is affected when static constructors are used. When you uncomment the static constructors for classes A and B you will see one of the earlier outputs from above. In my case, I see the first output set:

Init A._m
Init A._p
In A.X getter
Init B._r
Init B._t
In B.Y getter
After, A.X=999 B.Y=999

Your most natural reaction will probably be, "Well, that wasn't very compelling." The difference is that with the static constructors defined, §10.12 of the C# Specification kicks into effect. The CLR now executes the static initializers not "...at an implementation-dependent time prior to the first use of a static field of that class", but rather when the first static member of the class is referenced. In other words, the time when the static initializers execute is now predictable. In this case, the get accessor for class A was referenced before that of class B in the call to Console.WriteLine(), hence, class A's static initializers were invoked before those of class B. In this example, both static constructors were empty. If a static constructor contains code, as it usually will, the class' static initializers are executed immediately prior to the body of the static constructor.


Static Initializer Circular Dependencies


When the static inializers from two or more classes have mutual dependencies, things can get a little dicey. But if you know the rules (well, patterns, actually) and keep your cool, you'll find things a shade better than chaotic. We'll now take a variation of an earlier program containing static constructors for classes A and B. With both static constructors in place, we know that static initializers will not execute until a static member from the respective class is referenced. Keep this in mind as we look at the program's output.

using System;

class Test {
	static int count = 0;

	static void Main() {
		Console.WriteLine("In Main(), A.X=" + A.X);
	}

	public static int F(string message) {
		Console.WriteLine("Begin F " + message);
		int result = F_Internal(message);
		Console.WriteLine("End F " + message);

		return result;
	}

	// Keep track of the number of times F_Internal is called.
	private static int internalCalls = 0;

	private static int F_Internal(string message) {
		int startCount = ++internalCalls; // capture call count in local variable
		Console.WriteLine("Begin F_Internal: {0}, startingCount={1}", message, startCount);

		A.X = ++count;
		Console.WriteLine("\tA.X has been set to {0}, startingCount={1}", A.X, startCount);

		B.Y = ++count;
		Console.WriteLine("\tB.Y has been set to {0}, startingCount={1}", B.Y, startCount);

		Console.WriteLine("End F_Internal: {0}, startingCount={1}", message, startCount);
		return 999;
	}
} // class Test

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

class B {
	static B() { }
	public static int R = Test.F("Init B.R");
	public static int Y = Test.F("Init B.Y");
} // class B

Aside from the static constructors, the first thing to point out is the circurlar dependencies between A and B's static initializers. Both class' static initializers call Test.F(), which calls Test.F_Internal(), within which, static fields from both classes are referenced. (You may be wondering why Test.F_Internal() exists. We'll see why shortly.) The obvious result of this circularly dependent relationship is that A's static initialziers will have to be invoked from within B's static initializers and vice versa.

Let's have a first look at output when both class' static constructors come to the party. The highlighted lines represent the output from B's static initializers.

Begin F Init A.U
Begin F_Internal: Init A.U, startingCount=1
        A.X has been set to 1, startingCount=1
Begin F Init B.R
Begin F_Internal: Init B.R, startingCount=2
        A.X has been set to 3, startingCount=2
        B.Y has been set to 4, startingCount=2
End F_Internal: Init B.R, startingCount=2
End F Init B.R
Begin F Init B.Y
Begin F_Internal: Init B.Y, startingCount=3
        A.X has been set to 5, startingCount=3
        B.Y has been set to 6, startingCount=3
End F_Internal: Init B.Y, startingCount=3
End F Init B.Y
        B.Y has been set to 2, startingCount=1
End F_Internal: Init A.U, startingCount=1
End F Init A.U
Begin F Init A.X
Begin F_Internal: Init A.X, startingCount=4
        A.X has been set to 7, startingCount=4
        B.Y has been set to 8, startingCount=4
End F_Internal: Init A.X, startingCount=4
End F Init A.X
In Main(), A.X=999

Remembering what we learned from §10.5.5.1 and §10.12 of The C# Specification, the output is just what we'd expect. Let's walk through the output and relate it to The C# Specification.

The first reference to a static member is to A.X within the Console.WriteLine() on line 7 in Main(). This causes the CLR to execute A's static initializers where Test.F() followed by Test.F_Internal are called. At line 28 execution reaches the first static refernce to a member of class B in assigning the next value of count to B.y. What should happen next? We're not finished executing A's static initializers yet. Nonetheless, the CLR temporarily stops executing A's static initializer after the third line of output. Before B's static initializer begins, however, note that the right-hand side of the assignment statement on line 28 has already been calculated and its value of 2 is sitting on the stack, waiting to be assigned to B.Y. This assignment, however, will have to wait for B's static initializers to complete execution.

Upon encountering the assignment to B.Y on line 28, the CLR fires up B's static initializers, producing the highlighted output on lines 4 through 15. Now, you might be wondering what happens when, during the execution of B's static initializer we hit the assignment to A.X at line 25 of the program. Since the CLR has already started executing A's static initializer (remember, that's how B's static initializers got triggered in the first place), nothing special happens. A.x is assigned next values of count as we can see from output lines 6 and 12. The fact that A's static initializers did non re-run is actually an important point, so let me say it again:

If, while executing a class' static initializers, the CLR finds it necessary to initiate the static initializers of a second class, the static initializers for the first class are temporarily interrupted while the those of the second class execute. Upon completion of the second class' static initializers, the first class' static initializers resume at the point of interruption.

You might wonder where I looked up the above tidbit of knowledge. Honestly, the above is simply an observation I made from several examples involving static initializers. I'm not aware of anyplace in The C# Specification that formally describes this behavior. We'll see more examples of this behavior in a moment.

Once B's static initializers complete execution we pick up where A's static initializers left off, assigning the value of 2 to B.Y on line 28 (recall this value was calculated on line 28 prior to the triggering of B's static initializers). To reassure yourself that's this is exactly what's happening, notice the value of 1 printed for the startingCount variable on lines 16 and 17. From there out, it's simply the continuation of A's static initializers through to the output on line 24.

We've just looked at an example where both classes supplied static constructors. In the next three examples we'll turn off static constructors for class B, then for class A and finally for both classes B and A. We'll see again class B's static initializers interrupting those of class A. But when one or more static constructors are absent, the point of interruption is less predictable, which is consistent with what we saw at the beginning of the article where the CLR was at liberty to execute static initializers "...at an implementation-dependent time prior to the first use of a static field of that class."

Next we want to take the same program shown above and comment out class B's static constructor. With B's static constructor commented out, this is the output I see. As before, the output from B's static initializers is highlighted.

Begin F Init A.U
Begin F Init B.R
Begin F_Internal: Init B.R, startingCount=1
        A.X has been set to 1, startingCount=1
        B.Y has been set to 2, startingCount=1
End F_Internal: Init B.R, startingCount=1
End F Init B.R
Begin F Init B.Y
Begin F_Internal: Init B.Y, startingCount=2
        A.X has been set to 3, startingCount=2
        B.Y has been set to 4, startingCount=2
End F_Internal: Init B.Y, startingCount=2
End F Init B.Y
Begin F_Internal: Init A.U, startingCount=3
        A.X has been set to 5, startingCount=3
        B.Y has been set to 6, startingCount=3
End F_Internal: Init A.U, startingCount=3
End F Init A.U
Begin F Init A.X
Begin F_Internal: Init A.X, startingCount=4
        A.X has been set to 7, startingCount=4
        B.Y has been set to 8, startingCount=4
End F_Internal: Init A.X, startingCount=4
End F Init A.X
In Main(), A.X=999

Now this is unique. As before, we see that A's static initializers produce the output on line 1 but the call to F_Internal() is interruped by the execution of B's static initializers, producing lines 2 through 13 of the output. A's static initializers do not even set foot in F_Internal(). What seems to be happening here is that the CLR "notices" F_Internal() contains references to a class (B, obviously) whose static initializers have not yet been invoked. Rather than allow control to even enter F_Internal() the CLR immediately invokes B's static initializers. In the course of executing B's static initializers, references are made to static variables in A, but just as we saw when in the previous example when both static constructors were enabled, this does not cause A's static initializers to "re-start" or B's static initializers to relinquish execution to those of A. A's static initializers have already started and are simply and temporarily interrupted by those of B. As we see on lines 14 through 24, A's static initializers resume after B complete.

Recalling the specifics of what The C# Specification has to say about when static initializers can execute, the above output is consistent with what we should expect. Remember (as if you could ever forget it by now) that in the absence of a static constructor, the CLR can execute static initializers for a class anytime it sees fit, so long as their execution completes by the time the first reference is made to a static field in the class. In the output above, the CLR saw fit to initiate B's static initializers upon entry to the F_Internal() method.

Now we'll move on to the case where B's static constructor exists but A's does not. Before you view the output, go back to the program and see if you can predict a valid possible output. Here's the output I see. Once again, the output from class B's static initializers is highlighted.

Begin F Init A.U
Begin F_Internal: Init A.U, startingCount=1
        A.X has been set to 1, startingCount=1
Begin F Init B.R
Begin F_Internal: Init B.R, startingCount=2
        A.X has been set to 3, startingCount=2
        B.Y has been set to 4, startingCount=2
End F_Internal: Init B.R, startingCount=2
End F Init B.R
Begin F Init B.Y
Begin F_Internal: Init B.Y, startingCount=3
        A.X has been set to 5, startingCount=3
        B.Y has been set to 6, startingCount=3
End F_Internal: Init B.Y, startingCount=3
End F Init B.Y
        B.Y has been set to 2, startingCount=1
End F_Internal: Init A.U, startingCount=1
End F Init A.U
Begin F Init A.X
Begin F_Internal: Init A.X, startingCount=4
        A.X has been set to 7, startingCount=4
        B.Y has been set to 8, startingCount=4
End F_Internal: Init A.X, startingCount=4
End F Init A.X
In Main(), A.X=999

This output is different from the one before, as we would expect. Because B has a static constructor, the CLR will not initiate B's static initializers until it encounters the first reference to a static member of B, and that happens on line 28 of the program as A's static initialziers are running. A's static initializers are, as we've seen several times previous, interrupted and then resumed upon completion of B's static initialziers.

Finally, we look at the case where neither A nor B has a static constructor. I'm not going to to show the output from this scenario because it happens to be the exact same as what we saw when B's static constructor was commented out. Since you know that in the absence of static constructors the CLR has the option of when to run a class' static initializers, you also know that the output could have been different. It could have been the case that the CLR decided to run B's static initializers first in which case the output of B's static initialziers would have been interrupted by those of A, as control reaches the reference to A.X at line 25 of the program.


Static Initializers in the Face of JIT Optimization


We're about finsihed now except for an interesting tidbit I wanted to point out. You're really going to like this. In the course of writing this article I came across an example where the code behaves differntly depending on whether I execute the Debug or Release builds. Let me first show you the code and you can decide what the output should be. I'll tell you now that the both the Debug and Release outputs are "correct" in that The C# Specifciation allows either one. Notice that the static constructor is commented out.

using System;

class Test {
	static int value = 0;
	static int a = Initialize("Assigning a");
	static int b = Initialize("Assigning b");
	static String name = "Foo";
	static int c = Initialize("Assigning c");

	// static Test() { }

	static int Initialize(String mssg) {
		++value;
		Console.WriteLine("In Initialize() :: {0}, name={1}, returning {2}", mssg, name, value);
		return value;
	} // Initialize()

	static void Main() {
	}// Main()
} // class Test

There you have it. Here's the output I see when running under a Debug build:

In Initialize() :: Assigning a, name=, returning 1
In Initialize() :: Assigning b, name=, returning 2
In Initialize() :: Assigning c, name=Foo, returning 3

It's pretty obvious what's happening here, isn't it? The static initializers for the class are executing. This should come as no surprise based on what you've read in this article. Now when we execute the Release build of this program let me show you the output:


Notice the lack of output. What's going on? Remember what I've been telling you. In the absence of a static constructor the CLR will decide when (and if) to run static initializers. In this case, because none of the static fields was referenced, the static initializers did not run. I have to be a little more honest with you here. In the Release build, the .NET Runtime Optimizer performs an optimization by removing the unneccessary calls to the static initializers. Since the static fields in the above code are never referenced, there's really no need to call their initializers. The Optimizer was able to remove these needless calls generated by the compiler, hence there is no output when running the Release build.

In the program above the static initializers did nothing more than print out a simple diagnostic message and assign some variables that were unused so the correctness of the program is unlikely to be affected by the CLR "optimizing away" the static initilaizer calls, or even the static variables altogether, for that matter. But what if something more significant had been taking place in the Initialize() method? What if the method was writing something to a database or sending a message to a service? Granted, a static initializer is probably not the place to do these types of things but if one of your co-workers was to do this the code could be optimized away bythe CLR. Note again that this "optimizing away" of static initializers is only a danger if none of the static fields in the class are referenced. One way to ensure the static inializers for a class execute is to reference at least one of the static variables. For example, if Main() had been written as:

static void Main() {
	String k = name;
}// Main()

The static initializers for the class would have run due to the reference to the name fields. Let us digress for a moment and discuss in a bit more detail what caused the Release build to use of the .NET Runtime Optimizer.

This switching on and off of the .NET Runtime Optimizer is controlled by the System.Diagnotstics.DebuggableAttribute class applied to the assembly. I'm not going to pretend I know about all the ins and outs of using this Attribute but I do know that, by default, a Debug build of an application will apply the DebuggableAttribute to the assmebly (even though it will not appear in the AssemblyInfo.cs file Visual Studio generates). When disassembling the code I noticed the following DebuggableAttribute setting. Note the DisableOptimizations flag passed as part of the constructor. The Debug build has optimizations disabled, resulting in the un-empty output.

// Disable Runtime Optimizations - Used in Debug Build
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.Default)]

If you were to take the above Attribute, as it's written, and explicitly place it in the AssemblyInfo.cs file, it would effectively turn off optimizations, resulting in the Debug and Release versions both exhibiting the same non-empty output. Similarly, placing the DebuggableAttribute shown below in AssemblyInfo.cs would turn on runtime optimizations and no output would be produced for either the Debug or Release builds of the program.

// Enable Runtime Optimizations - Used in Release Build
[assembly: Debuggable(true, false)]

In Summary: Tidbits to Remember


I want to summarize the important tidbits you'll need to remember from what we discussed in this article. If you can memorize these salient points you'll be streets up on the competition.

  1. Field initializers execute in the textual order in which they're declared in the containing class. This will tell you the order of variable initialization with the containing class.
  2. Prior to the execution of a variable's initialzier, the CLR assigns default values to each variable based on its type. The types and their corresponding default values can be found here.
  3. Instance field initializers cannot reference the instance being created (i.e., the this object).
  4. If a class contains a static constructor, the static initializers for the class (if there are any) execute immediately prior to the execution of the static constructor. In fact, you can think of the static initializers as being prepended to the body of the static constructor.
  5. If a class contains a static constructor, its execution is triggered by the first of the following events:
    • An instance of the class type is created.
    • Any of the static members of the class type are referenced.
  6. If a class does not contain a static constructor, the CLR guarantees class' static initializers (if there are any) to have executed at some indeterminate time prior to the first reference to a static field in the class.
  7. If, while executing a class' static initializers, the CLR finds it necessary to initiate the static initializers of a second class, the static initializers for the first class are temporarily interrupted while the those of the second class execute. Upon completion of the second class' static initializers, the first class' static initializers resume at the point of interruption.
  8. At runtime the CLR may "optimize away" calls to static initializers if it can determine no static fields were actually referenced. For this reason, you want to be be very careful about the code that executes when initializing static variables. If you have code that absolutely must execute in a static context, place the code in the static constructor of a class for which you are sure a static memeber will be referenced from another part of the program.
Γ# Home3.135.206.19

If you'd like to contact me regarding something on this site feel free to .