Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the static variable initialization order across classes in C#?

Tags:

c#

wpf

DependencyProperty.AddOwner MSDN page offers an example with two classes with static members, and the member of one class depends on the member of the other class for initialization. I think MSDN is wrong - the initialization order of static variables is unreliable in C# just like it is in C++ or anywhere else. I'm probably wrong because the WPF library itself is written that way and it works just fine. What am I missing? How can C# compiler possibly know the safe initialization order?

like image 623
CannibalSmith Avatar asked Sep 10 '09 14:09

CannibalSmith


People also ask

What is the order of static variable initialization across one program?

Within a single compilation unit, static variables are initialized in the same order as they are defined in the source (this is called Ordered Dynamic Initialization). Across compilation units, however, the order is undefined: you don't know if a static variable defined in a.

How are static variables initialized in C?

In C, static variables can only be initialized using constant literals.

What are static variables initialized to?

A static variable is initialized only once (since this is part of the declaration process) and will be initialized to 0 unless the programmer designates otherwise. Subsequent invocations of the function in which a static variable resides will retain the last value of that variable.

Are static variables initialized first?

It is a variable which belongs to the class and not to object(instance ). Static variables are initialized only once, at the start of the execution. These variables will be initialized first, before the initialization of any instance variables.


1 Answers

It's fine for one type to depend on another type being initialized, so long as you don't end up in a cycle.

Basically this is fine:

public class Child
{
    static Child() {} // Added static constructor for extra predictability
    public static readonly int X = 10;
}

public class Parent
{
    static Parent() {} // Added static constructor for extra predictability
    public static readonly int Y = Child.X;
}

The result is well-defined. Child's static variable initializers are executed prior to the first access to any static field in the class, as per section 10.5.5.1 of the spec.

This isn't though:

public class Child
{
    public static readonly int Nasty = Parent.Y;
    public static readonly int X = 10;
}

public class Parent
{
    public static readonly int Y = Child.X;
}

In this latter case, you either end up with Child.Nasty=0, Parent.Y=10, Child.X=10 or Child.Nasty=0, Parent.Y=0, Child.X=10 depending on which class is accessed first.

Accessing Parent.Y first will start initializing Parent first, which triggers the initialization of Child. The initialization of Child will realise that Parent needs to be initialized, but the CLR knows that it's already being initialized, so carries on regardless, leading to the first set of numbers - because Child.X ends up being initialized before its value is used for Parent.Y.

Accessing Child.Nasty will start initializing Child first, which will then start to initialize Parent. The initialization of Parent will realise that Child needs to be initialized, but the CLR knows that it's already being initialized, so carries on regardless, leading to the second set of numbers.

Don't do this.


EDIT: Okay, more detailed explanation, as promised.

When is a type initialized?

If a type has a static constructor, it will only be initialized when it's first used (either when a static member is referenced, or when an instance is created). If it doesn't have a static constructor, it can be initialized earlier. In theory, it could also be initialized later; you could theoretically call a constructor or a static method without the static variables being initialized - but it must be initialized before static variables are referenced.

What happens during initialization?

First, all static variables receive their default values (0, null etc).

Then the static variables of the type are initialized in textual order. If the initializer expression for a static variable requires another type to be initialized, then that other type will be completely initialized before the variable's value is assigned - unless that second type is already being initialized (due to a cyclic dependency). Essentially, a type is either:

  • Already initialized
  • Being initialized at the moment
  • Not initialized

Initialization is only triggered if the type is not initialized. This means that when there are cyclic dependencies, it is possible to observe a static variable's value before its initial value has been assigned. That's what my Child/Parent example shows.

After all the static variable initializers have executed, the static constructor executes.

See section 10.12 of the C# spec for more details on all of this.


By popular demand, here was my original answer when I thought the question was about the initialization order of static variables within a class:

Static variables are initialized in textual order, as per section 10.5.5.1 of the C# spec:

The static field variable initializers of a class correspond to a sequence of assignments that are executed in the textual order in which they appear in the class declaration.

Note that partial types make this trickier as there's no one canonical "textual order" of the class.

like image 179
Jon Skeet Avatar answered Oct 01 '22 20:10

Jon Skeet