8

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

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

注意:我不是在问如何修复该代码,因为我已经知道如何做到这一点

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

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

4

4 回答 4

12

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

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

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

于 2009-03-18T21:43:11.587 回答
6

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

考虑这样的事情:

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

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

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

于 2009-03-19T00:23:27.957 回答
1

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

像这样

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

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

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

于 2009-03-18T21:33:01.720 回答
1

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

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

请参阅C# 规范中的变量初始化程序或有关初始化程序的这篇文章。此外,C# 中静态构造函数/初始化程序的问题顺序是相关的。

于 2009-03-18T21:34:36.083 回答