Mr. Smith
Mr. Smith

Reputation: 4506

Is the static initialization order of this code implementation specific?

I have a design that relies heavily on static initialization. I've noticed that after a series of OS updates, my design appears to be failing on some older versions of the .NET Framework (v<3.5), and only under Release configuration.

I think I've been able to narrow the issue down to a block of code similar in design to this:

public abstract class Foo { public static object A; }
public class Bar : Foo { 
    public static object B = InitB();
    private static object InitB(){ return A }; }

public static void Main()
{
    Foo.A = new object();
    Bar bar = new Bar();
    Console.Write((bar.B==null).ToString());
}

On .NET 2.0, under Release build, on my system, it appears my code is printing true. Whereas on .NET 4.5, it's printing false. Is the behavior of the code above implementation specific?

Upvotes: 2

Views: 81

Answers (2)

James
James

Reputation: 82096

Is the behaviour of the above code implementation specific

For the example above, the docs would suggest that is the case

If a static constructor 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.

For consistency across .NET versions, and to force initialization order, you should add a static constructor to both classes.

Upvotes: 0

user743382
user743382

Reputation:

Your code relies on Bar's static constructor being called after the assignment to Foo.A. The language spec does not guarantee this. It only guarantees it if you actually write a static constructor, not if the compiler implicitly generates one: in that case, it may be called earlier than you expect.

To make sure your code behaves the same way in all valid implementations of .NET Framework, add a static constructor. You don't need to re-factor your initialisers, they can remain where they are.

public class Bar : Foo { 
    static Bar() { } // <-- add this
    public static object B = InitB();
    private static object InitB() { return A };
}

Alternatively, re-work your code in such a way that it still works even if the static constructor is called early.

Upvotes: 1

Related Questions