【问题标题】:Why in C# does order matter for static initialization?为什么在 C# 中顺序对于静态初始化很重要?
【发布时间】:2010-10-14 04:43:33
【问题描述】:

此代码在 C# 中具有明确定义的不工作行为:

class Foo
{
    static List<int> to = new List<int>( from ); // from is still null
    static IEnumerable<int> from = Something();
}

注意:我不是在问如何将代码修复为 I already known how to do that

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

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

【问题讨论】:

  • 我认为你回答自己说这是“定义明确的行为”。

标签: c# language-theory


【解决方案1】:

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

像这样

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

    static Foo()
    {
        from = Something();
        to = new List<int>(from);
    }
}

至于为什么 C# 不在第一次访问时执行此操作,我只是认为当有其他替代方案可以明确发生的情况时,不需要这种复杂性。

【讨论】:

  • 我阅读了这个问题。问为什么 C# 以一种方式做某事,永远不会给你太多有用的答案。我的回答是这样的,当你能做到这一点时,为什么要这样做......
  • 询问为什么某些东西在 C# 中有效已经很多次了;看看 Jon Skeet 对 C# 的机制了解多少。
  • 最好用初始化方法,FXCop会告诉你的。
  • 不管 FXCop 告诉你什么,这都不能回答问题。
  • 是的,但有什么意义呢?它不会改变。此外,在您投反对票之前,我已经回答了为什么,而另一个答案也没有说明原因。
【解决方案2】:

C# 会进行运行时检查以检测对类的首次访问,但不会对类中的静态初始化重新排序。

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

请参阅 C# 规范中的 Variable initializers 或有关初始化程序的 this article。此外,问题 Order of static constructors/initializers in C# 是相关的。

【讨论】:

  • 我问了这个问题:b 另请参阅我对 Ray 的评论。我/不是/询问如何修复该代码。
  • 是的,你做到了。 :-) 我想我应该多加注意!
  • "'有问题,请联系系统管理员',克鲁德!我愿意,但我 /am/ 系统管理员!"
【解决方案3】:

初始化器只是一种语法糖。编译器在编译您的类时将该代码放入 .cctor 中,并按照它们在代码中的排列顺序推送它们。

它不运行任何检查,因为它没有意义。你仍然可以有初始化周期,所以它无论如何都行不通。

如果你有兴趣,我前段时间写过博客:

【讨论】:

  • 这是主要原因:编译器无法解析的初始化周期。
  • 循环总是一个错误:我宁愿得到编译器错误而不是你现在得到的。除了周期,我看不到任何问题。 +1
  • >"编译器将该代码放入 .cctor 中。"这肯定是不对的。初始化器的调用顺序与构造器不同,对吧?
【解决方案4】:

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

考虑这样的事情:

class Foo
{
    static string header = Bar.GetHeader();
    static string version = Bar.GetVersion();
}

Bar.GetVersion 假定Bar.GetHeader 已被调用。如果编译器可以随意更改初始化顺序,那么程序员就无法保证初始化顺序。

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

【讨论】:

  • 一个好点,这可能是原因。也就是说,我认为“按顺序评估”的方式是错误的解决方法。我认为正确的做法是说,“如果顺序很重要,请在构造函数中初始化。”和“依赖于内联初始化顺序的代码是非法的,即使它运行”。
猜你喜欢
  • 1970-01-01
  • 2021-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-07
  • 2015-06-01
  • 1970-01-01
相关资源
最近更新 更多