单个C#类中静态成员初始化顺序

4

考虑以下具有两个静态成员变量的类代码段:

            public static class Foo
            {

                static string A = GetA(B);
                static string B = "required for A";
                ...

现在我的理解是,只有在第一次访问AB时它们才会被初始化。然而,当我执行了上面的片段的一个完整版本,其中AB初始化之前被访问时,会导致null传递给GetA(),而不是"required for A"。为什么行为不是开始初始化A,然后当意识到需要初始化A时,初始化B,然后返回完成初始化A呢?
这方面有哪些通用规则?为什么会这样呢?我看到其他问题也涉及到这个问题(C#中静态变量何时初始化?),但它们并没有完全回答这个问题。 C#中的静态变量初始化顺序是什么?主要讨论了跨类的工作方式,而不是单个类内部的工作方式(尽管Jon Skeet对他的答案进行了补充,“按照大众的需求,这是我认为问题是关于类内部静态变量的初始化顺序时的原始答案:...”,但它被埋在一个更长的答案中)。

@Alexei Levenkov,请看我的编辑,了解我为什么认为这个问题应该与您链接的问题分开考虑。基本上,虽然我的问题的答案被埋在John Skeet对您链接的问题的答案中,但链接的问题主要涉及如何在类之间工作,而不是在单个类内部。 - Adam
1个回答

5
简而言之,不要这样做。 标准 ECMA-334 C# 语言规范 静态字段初始化:类的静态字段变量初始值设定项相当于在类声明中按它们出现的文本顺序执行的一系列赋值(§15.5.6.1)。在部分类中,“文本顺序”的含义由 §15.5.6.1 指定。如果类中存在静态构造函数(§15.12),则在执行该静态构造函数之前立即执行静态字段初始值设定项。否则,在第一次使用该类的静态字段之前的实现相关时间执行静态字段初始值设定项。
修复方法是:
- 将它们按顺序放置在 Static Constructor 中使用, - 或者在一个 Static Constructor 中直接初始化它们,从而让你能够控制初始化的顺序(根据上述信息)。
个人建议在 Static Constructor 中进行初始化,这样似乎更加具体和易懂,并且不太可能在重构时受到影响。

好的,我理解通常情况下事物是“按照它们出现的文本顺序执行”的。但是如果一个静态字段的初始化取决于另一个静态字段的值,会发生什么呢?这是否会改变初始化的顺序,即需要初始化的静态字段将首先被初始化?我的例子似乎表明这不是这种情况... - Adam
总的来说,我还是有些困惑。静态字段是按照文本顺序初始化的,还是取决于首先访问哪些字段? - Adam
看了你的答案和Jon Skeet给Alexei Levenkov问题的答案,我认为这是答案:_在_类中,静态成员按文本顺序初始化。_跨_类有点更复杂,但简而言之,“如果静态变量的初始值表达式需要另一种类型进行初始化,则该另一种类型将在变量的值被分配之前完全初始化 - 除非由于循环依赖关系已经初始化了第二个类型。”我认为这里的“类型”是"类"的同义词。 - Adam
@Adam 是的,Jon的答案更加精确,但前提是,由于您有一个空问题,需要在构造函数中初始化它们,因为您可以完全控制顺序。没有实现复杂性,重构也不会影响逻辑。这也使得理解正在发生的事情以及原因更容易。无论如何,是的,您的结论似乎非常正确,祝你好运。 - TheGeneral

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接