7

Possible Duplicate:
What is the static variable initialization order in C#?

For fun i ran this code

I was not expecting 2 2 3. I was expecting a compiler error (circlur dependency) or 8 5 3.

What are the rules to initialization order in C#?

-edit- i tried making a not static and i got what i expected. Why is b 2 before and now 5. I don't think i'm going to like the rules... Luckily i never do anything like this so i haven't had a problem.

using System;

public class Test
{
        public static void Main()
        {
                A.t();
        }
}

class A
{
    static int a = B.b + c;
    public static int c = 3;
    static public void t()
    {
        Console.WriteLine("{0} {1} {2}", a, B.b, c);
    }
}
class B
{
    public static int b = A.c+2;
}
Community
  • 1
  • 1
  • 1
    If you think that is fun: imagine you have partial classes, so there is no defined textual order: http://stackoverflow.com/questions/7965830/is-the-textual-order-across-partial-classes-formally-defined – Marc Gravell Feb 17 '12 at 21:07

5 Answers5

6

Initialisation is per-type when needed (beforefieldinit notwithstanding). Withing a class: "textual order":

§17.11 in ECMA 334:

If a class contains any static fields with initializers, those initializers are executed in textual order immediately prior to executing the static constructor.

It doesn't apply for instance fields, since you can't use instance values in a field initializer.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • How does that work with circular dependencies? – Cameron Feb 17 '12 at 21:05
  • 1
    @Cameron it explicitly doesn't attempt to. It processes them in "textual order", I.e. top to bottom. – Marc Gravell Feb 17 '12 at 21:06
  • What cameron said. It looks like once it enters "A" it doesn't try to initialize 'c' when B.b tries to access it. But i believe i understand how it works. (proibably will accept this answer) -edit- saw your common. oh. undefined i guess. Thats unfortunate. mono and ms give the same results tho which is good. –  Feb 17 '12 at 21:07
  • @acidzombie if the type initializer is already in progress, it just runs with the current values, whatever they are. This is required since initializer can be re-entrant. Of course, knowing **exactly** when a type initializer is going to fire is even harder! – Marc Gravell Feb 17 '12 at 21:09
3

It all makes perfect sense. Here is the sequence of events:

  1. You call A.t
  2. Since this is the first use of A, its static members a is initialized to B.b + c
    • Since this is the first use of B, its static member b gets initialized to A.c+2. This is not the first use of A, so A.c is read directly. Since it has not been statically initialized yet, it's still set to its default value of 0. Hence B.b becomes 2.
    • At this point, A's static initializer adds 2 from B.b to 0 from A's own c, which remains set to the default value of 0.
  3. The sequence of static intialization continues with setting A.c to 3.
  4. Now A is ready to use, and t() proceeds to printing 2 2 3, according to the values stored in the corresponding fields of A and B.
Cameron
  • 96,106
  • 25
  • 196
  • 225
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
2

If I were you, I'd always assume that your compiler initializes variables in a random(unknown) order.

By the way, static variables are associated with your class, and not any instance of your class. they're essentially global variables.

  • 1
    That's a very good assumption usually. Even though the order IS specified in the spec, it's very bad practice (IMO) to rely on the initialization order. It makes your code completely unreadable, and I can't seem to think of a single reason why you would do this normally. – Erik van Brakel Feb 17 '12 at 21:13
2

Initialization happens in the order it appears within a class. So this is what's going on here:

  1. A is initialized. It starts to set A.a but needs B, so...
  2. B is initialized. B.b gets set - A.c is valid but hasn't been initialized yet, so it's 0. B.b becomes 2.
  3. A.a gets set to B.b (2) + c (which hasn't been set yet - so 0). A.a is now 2.
  4. Finally, c is set to 3.
Rophuine
  • 724
  • 3
  • 8
  • Thats what i assume after my edit/2nd test. I don't like that idea. I rather get a compile error :x –  Feb 17 '12 at 21:14
0

-edit- i know i used static but please explain non static. I'll test with nonstatic in a minute

You don't have this problem with non-static fields, because you can't read an instance field of an object that has not yet been constructed.

Igor ostrovsky
  • 7,282
  • 2
  • 29
  • 28