How does static field initialization work in C#?
Should static field initialization be completed before constructor is called?
The following program provides output that seems incorrect to me.
new A()
_A == null
static A()
new A()
_A == A
The code:
public class A
{
public static string _A = (new A()).I();
public A()
{
Console.WriteLine("new A()");
if (_A == null)
Console.WriteLine("_A == null");
else
Console.WriteLine("_A == " + _A);
}
static A()
{
Console.WriteLine("static A()");
}
public string I()
{
return "A";
}
}
class Program
{
static void Main(string[] args)
{
var a = new A();
}
}
Solution 1:
This is correct.
Your static initializers, then the static constructor is run before your standard constructor, but when it runs, it's using new A(), so passing through your non-static constructor path. This causes the messages you see.
Here is the full path of execution:
When you first call var a = new A();
in your program, this is the first time A is accessed.
This will fire off the static initialization of A._A
At this point, A._A constructs with _A = (new A()).I();
This hits
Console.WriteLine("new A()");
if (_A == null)
Console.WriteLine("_A == null");
since at this point, _A hasn't been set with the returned, constructed type (yet).
Next, the static constructor A { static A(); }
is run. This prints the "static A()" message.
Finally, your original statement (var a = new A();
) is executed, but at this point, the statics are constructed, so you get the final print.
Solution 2:
One extra side note - the C# specification (I'm looking at 4.0, but it's there in 3.0 too) says in 10.5.5.1 Static Field Initialization:
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.
You have a static constructor, so the "Otherwise" clause does not apply. But I think it's relevant information to your question to know that if you don't have a static constructor, the static field initializers can be executed 'at an implementation-dependent time'. This could matter if your static field initializer is doing some type of data initialization or object creation which you rely on without accessing the static field itself.
It is esoteric, I guess, but I saw it happen today as the 'implementation-dependent time' appears to have changed between C# 3.0 and 4.0 - at least for the situation I was looking at. The easy solution of course is simple - just add a static constructor...