Order of initialization of static members in yield return statements

I just noticed that the initialization of the static members which are returned via yield return is not in the order they are enumerated but in reverse order. Although the C1 instance is returned as first item of the iterator, the C2 instance is created first. If yielding more than 2 items, the last one is initialized first.

public abstract class B
{
    private static int _number;

    protected B()
    {
        Number = ++_number;
    }
    public int Number { get; private set; }
}

class C1 : B
{
    public static readonly C1 Default = new C1();
}

class C2 : B
{
    public static readonly C2 Default = new C2();
}

public static IEnumerable<B> GetItems()
{
    yield return C1.Default;
    yield return C2.Default;
}

private static void Main(string[] args)
{
    var items = GetItems();

    foreach (var item in items)
    {
        Console.WriteLine(item.Number);
    }
}
  • Is there a special reason why it is reversed?
  • Is this somewhere defined in the specification - or is it undefined and may change at some time in the future?
  • I would prefere if the items are constructed in the order I use them. Is there a way to ensure this?
Jon Skeet
people
quotationmark

As per the question comment, static initialization is not always deterministic. However, you can make it deterministic using static constructors:

class C1 : B
{
    static C1(){}
    public static readonly C1 Default = new C1();
}

class C2 : B
{
    static C2(){}
    public static readonly C2 Default = new C2();
}

That forces each of C1 and C2 to be initialized exactly at the point of first reference - neither earlier than that nor later than that. (Where "at the point of first reference" is defined to be construction of an instance or access to a static member.)

Without a static constructor, type initialization can be eager (i.e. occurs before you first use a type) or surprisingly late. You can create instances, call static and instance methods on a type and still not run the static field initializers - it's only when you refer to a static field that the static field initializers must have been run.

people

See more on this question at Stackoverflow