tags:

views:

661

answers:

5

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();
    }
}
+8  A: 

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.

Reed Copsey
Dang! Beat me to it!
Mitchel Sellers
With all due respect... static constructor doesn't run first. The static field initializer runs first.
Prankster
Construction of A._A happens in the static constructor. It's just that the compiler prepends all fields initializations in the static constructor (.cctor) before the code declared in C# static constructor.
Jb Evain
@prankster: I was just trying to say that his static construction + initialization is all happening prior to his non-static construction. I reworded and edited to be more clear.
Reed Copsey
A: 

Yes, static fields initialization should complete before constructor is called. But you put compiler in the unnormal situation and it just can't obey this rule.

This is interesting trick, but it's not gonna happen in normal application.

XOR
+1  A: 

I actually believe that it is doing what you think. Your test makes it hard to tell.

Your initalization for _A

public static string _A = (new A()).I();

First creates a new instance of A, thus your writings of new A() and _A = null. Because it was null when it started, as this is the initialization. Once initalized, the static constructor is called, which returns the new instance.

Mitchel Sellers
A: 

It seems the compiler is doing the expected.

1st - All static code is executed (fields first, then static constructor) in the class:

public static string _A = (new A()).I();

// and

static A()
{
    Console.WriteLine("static A()");
}

2nd - Class constructor is called:

public A()
{
    Console.WriteLine("new A()");
    if (_A == null)
        Console.WriteLine("_A == null");
    else
        Console.WriteLine("_A == " + _A);
}

You ask why this is possible. Well, in my opinion, an instance doesn't absolutely require that all class variables are initialized upon creation. It just requires they must exist. I think this particular case supports this thought because an instance is created before all static initialization is done.

bruno conde
A: 

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...

Hugh Robinson