views:

109

answers:

2

Hello everybody

Which static class initialize first if we have one more static classes in our project?

For example : Below code gives null exception.

class Program
    {
        static void Main(string[] args)
        {
            First.Write();
            Second.Write();
        }
    }
    static class First
    {
        public static int[] firstArray = new int[20];
        public static int[] secondArray = Second.secondArray;
        public static void Write()
        {
            Console.WriteLine(firstArray.ToString());
            Console.WriteLine(secondArray.ToString());
        }
    }
    static class Second
    {
        public static int[] firstArray = First.firstArray;
        public static int[] secondArray =secondArray = new int[30];
        public static void Write()
        {
            Console.WriteLine(firstArray.ToString());
            Console.WriteLine(secondArray.ToString());
        }
    }

If you give attention, you will see that if First class will initialize itself so secondArray field of Second would be null.But if Second class would initialize first so Second class firstArray would be null.I am trying to tell that which initialize first makes different results.

I think that it is abstract question about my project.I encounter it while trying to understand why i am getting unexpected results.

+10  A: 

First will begin to initialize, assign firstArray, then notice that it requires Second to be initialized in order to get the initial value of secondArray.

Second will start initializing, and then notice that it requires First to be initialized. However, the CLR will then notice that First is already initializing in the current thread, so it won't block. Second's initialization will complete, and then First's initialization will complete.

Fortunately, the field that Second needs has already been assigned, so the "right thing" happens.

That's all very well if First actually starts initializing first. However, as neither of the classes has a static constructor, it's possible that Second will start to initialize first... it would then start to initialize First, which would spot that Second is already initializing and take Second.secondArray's current value (null) for First.secondArray. This would be a Bad Thing. Note that the initialization timing for types without static constructors has changed in .NET 4 - not in a spec-breaking way, but possibly in an existing-code-breaking way.

If both First and Second had static constructors, then First would be initialized first, as that's the first class that Main touches.

Moral of the answer: don't do this. Type initializers which refer to each other are very error prone. For another example, see Eric Lippert and Neal Gafter's NDC 2010 talk, "C# Puzzlers" which can be viewed on the NDC video page.

Jon Skeet
Does the standard guarantee this order? My guess was that each class initialises at some undefined before the first access, which turns this into a dependency cycle that gets resolved randomly.
Tim Robinson
@Tim: I've updated my answer - with no static constructors, the order is indeed undefined.
Jon Skeet
With debugger attached to VS2005, a Bad Thing happens - `Second.firstArray` gets set to `null`
AakashM
And here I thought some of those puzzlers was purely academic :P
Lasse V. Karlsen
@Jon Skeet: After few test i see that changing write method ordering doesn't change result.First class constructor work first and again throw null exception.
Freshblood
@Freshblood: Do you mean changing the ordering to the *calls* to Write, or the ordering *within* the Write methods? The ordering of the calls in Main *will* make a difference if both types have static constructors.
Jon Skeet
Second.Write();First.Write(); It doesn't change static constructor initialize ordering If both has static contructors with different call ordering.
Freshblood
Sorry for my poor english if i still couln't explain what i am trying to say.I mean call ordering of methods is not dependant for static method initializers.
Freshblood
A: 

I don't believe there is any guarantee as to which static type is initialised first. To ensure fields are initialised properly this way, you'd need to add a static constructor, e.g.:

static class Second
{
    public static int[] firstArray = First.firstArray;
    public static int[] secondArray = new int[30];

    static Second() { }

    public static void Write()
    {
        Console.WriteLine(firstArray.ToString());
        Console.WriteLine(secondArray.ToString());
    }
}

Now, when you run the same thing again, it works...

Matthew Abbott