为什么在C#中,顺序对于静态初始化很重要?

为什么在C#中,顺序对于静态初始化很重要?,c#,language-theory,C#,Language Theory,这段代码在C#中有定义良好的不工作行为: class Foo { static List<int> to = new List<int>( from ); // from is still null static IEnumerable<int> from = Something(); } class-Foo { 静态列表到=新列表(从);//从仍然为空 静态IEnumerable from=某物(); } 注意:我不是问如何将代码修复为

这段代码在C#中有定义良好的不工作行为:

class Foo
{
    static List<int> to = new List<int>( from ); // from is still null
    static IEnumerable<int> from = Something();
}
class-Foo
{
静态列表到=新列表(从);//从仍然为空
静态IEnumerable from=某物();
}
注意:我不是问如何将代码修复为

这样做的理由是什么?C#已经执行运行时检查以检测对静态成员的首次访问。为什么不把它扩展到每个成员的事情,让它们按需运行,或者更好的是让编译器在编译时计算出顺序


顺便说一句:我认为同样的问题(或几乎相同)也适用于非静态成员。

我认为您需要使用的是静态构造函数

像这样

class Foo
{
    static List<int> to;
    static IEnumerable<int> from;

    static Foo()
    {
        from = Something();
        to = new List<int>(from);
    }
}
class-Foo
{
静态列表到;
静态IEnumerable from;
静态Foo()
{
from=某物();
to=新列表(从);
}
}
至于为什么C#在第一次访问时不这样做,我只是不认为有必要这样复杂,因为有其他替代方案可以清楚地说明发生了什么。

C#进行运行时检查以检测对类的第一次访问,但不在类内重新排序静态初始化

从上到下初始化静态字段,然后从上到下初始化静态构造函数。更改字段的顺序或创建静态构造函数并从tehre初始化字段


请参见C#spec或初始值设定项中的内容。。同样,这个问题也是相关的。

初始值设定项只是一种句法糖类。编译器在编译类时将该代码放入.cctor中,并按代码中的排列顺序进行压缩

它不运行任何检查,因为它没有意义。您仍然可以有初始化周期,因此它无论如何都不会工作

如果您感兴趣,我不久前在博客上写过:


由于其他静态类的副作用,我可以根据初始化顺序设想一个程序员。你我都知道依靠副作用是不好的做法,但这并不一定是非法的

考虑一下这样的情况:

class Foo
{
    static string header = Bar.GetHeader();
    static string version = Bar.GetVersion();
}
并且
Bar.GetVersion
假设调用了
Bar.GetHeader
。如果编译器可以随意更改初始化顺序,那么程序员将无法保证初始化顺序


丑陋,理所当然,但完全合法。如果您想象二阶效应(即调用的静态方法本身依赖于具有副作用的类),您会发现编译器不可能可靠地重新安排任何内容,就像编译器不可能(通常)重新安排静态构造函数中函数调用的顺序一样。

我阅读了这个问题。问C#为什么以一种方式做事,永远不会给你一个有用的答案。我的回答大致是这样的,当你能做到这一点时,为什么会这样……问为什么某些东西在C#中起作用已经有很多次了;看看Jon Skeet对C#的机制了解多少。最好使用初始化方法,FXCop会告诉你这一点。不管FXCop告诉你什么,这都不能回答问题。是的,但有什么意义?这不会改变的。另外,在你投反对票之前,我有一个关于为什么的答案,另一个答案也没有说明原因。这是主要原因:编译器无法解决初始化周期。周期总是一个错误:我宁愿得到编译器错误,而不是你现在得到的。除了周期之外,我看不到任何问题+1> “编译器将代码放入.cctor中。”这肯定是不对的。初始值设定项的调用顺序与构造函数不同,对吗?我问了这个问题:b也看到我对Ray的评论。我/不是/问如何修复该代码。是的,你做了。:-)我想我应该多加注意!“‘有点不对劲,请联系系统管理员’,克鲁德!我会的,但我/我/系统管理员!”这是一个很好的观点,可能就是原因。也就是说,我认为“按顺序评估”的方法是错误的。我认为正确的策略是说,“如果顺序很重要,在构造函数中初始化。”和“依赖于内联初始化顺序的代码是非法的,即使它运行”。我认为你回答自己说这是“定义良好的行为”。