yield return语句中静态成员的初始化顺序

Lio*_*nAM 3 c# ienumerable yield-return

我只是注意到,通过yield return返回的静态成员的初始化不是按照它们枚举的顺序,而是以相反的顺序.虽然C1实例作为迭代器的第一项返回,但首先创建C2实例.如果产生超过2个项目,则最后一个项目首先被初始化.

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);
    }
}
Run Code Online (Sandbox Code Playgroud)
  • 它有什么特别的原因可以逆转吗?
  • 这是在规范中定义的某个地方 - 或者它是否未定义并且可能在将来的某个时间发生变化?
  • 我会优先选择这些项目是按照我使用的顺序构建的.有没有办法确保这个?

Jon*_*eet 5

根据问题评论,静态初始化并不总是确定性的.但是,您可以使用静态构造函数使其具有确定性:

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

class C2 : B
{
    static C2(){}
    public static readonly C2 Default = new C2();
}
Run Code Online (Sandbox Code Playgroud)

这迫使每一个C1C2初始化恰好在第一次参考时 - 不早于那个,也不晚于那个.(其中"在第一次引用时"被定义为构造实例或访问静态成员.)

如果没有静态构造函数,类型初始化可能是急切的(即在您第一次使用类型之前发生)或者出乎意料地迟到.您可以创建实例,在类型上调用静态和实例方法,但仍然不运行静态字段初始值设定项 - 仅当您引用静态字段时必须运行静态字段初始值设定项.