【问题标题】:What are the rules to initialization order in C#? [duplicate]C#中初始化顺序的规则是什么? [复制]
【发布时间】:2012-02-18 05:28:56
【问题描述】:

可能重复:
What is the static variable initialization order in C#?

为了好玩,我跑了this code

我没想到2 2 3。我期待一个编译器错误(circlur 依赖)或8 5 3

C#中初始化顺序的规则是什么?

-edit-i tried making a not static 我得到了我的预期。为什么之前是 b 2 而现在是 5。我不认为我会喜欢这些规则...幸运的是我从来没有做过这样的事情,所以我没有遇到问题。

using System;

public class Test
{
        public static void Main()
        {
                A.t();
        }
}

class A
{
    static int a = B.b + c;
    public static int c = 3;
    static public void t()
    {
        Console.WriteLine("{0} {1} {2}", a, B.b, c);
    }
}
class B
{
    public static int b = A.c+2;
}

【问题讨论】:

标签: c#


【解决方案1】:

需要时根据类型进行初始化(尽管在fieldinit 之前)。使用类:“文本顺序”:

ECMA 334 中的§17.11:

如果一个类包含任何带有初始化器的静态字段,则这些初始化器会在执行静态构造函数之前以文本顺序立即执行。

它不适用于实例字段,因为您不能在字段初始值设定项中使用实例值。

【讨论】:

  • 循环依赖如何工作?
  • @Cameron 它明确不尝试这样做。它以“文本顺序”处理它们,即从上到下。
  • 卡梅伦说的。看起来一旦进入“A”,当 B.b 尝试访问它时,它就不会尝试初始化“c”。但我相信我理解它是如何工作的。 (可能会接受这个答案) -edit- 看到你的共同点。哦。我猜是未定义的。那真不幸。 mono 和 ms 给出相同的结果,这很好。
  • @acidzombie 如果类型初始化程序已经在进行中,它只会使用当前值运行,无论它们是什么。这是必需的,因为初始化程序可以重入。当然,确切地知道类型初始化器何时触发更加困难!
【解决方案2】:

这一切都说得通。以下是事件的顺序:

  1. 您拨打A.t
  2. 由于这是A的第一次使用,它的静态成员a被初始化为B.b + c
    • 由于这是B 的第一次使用,它的静态成员b 被初始化为A.c+2。这不是第一次使用A,所以直接读取A.c。由于它还没有被静态初始化,它仍然被设置为其默认值0。因此B.b 变为 2。
    • 此时,A 的静态初始化程序将 B.b 中的 2 加到 A 自己的 c 中的 0,仍然设置为默认值 0
  3. 静态初始化序列继续将A.c 设置为3
  4. 现在A 可以使用了,t() 会根据AB 对应字段中存储的值继续打印2 2 3

【讨论】:

  • 这就是我在编辑/第二次测试后的假设。我不喜欢这个主意。我宁愿得到一个编译错误:x
  • @acidzombie24 我同意,这样的静态初始化器是邪恶的。
【解决方案3】:

如果我是你,我总是假设你的编译器以随机(未知)顺序初始化变量。

顺便说一句,static 变量与您的类相关联,而不是与您的类的任何实例相关联。它们本质上是全局变量。

【讨论】:

  • 这通常是一个很好的假设。即使在规范中指定了顺序,依赖初始化顺序也是非常糟糕的做法(IMO)。它使您的代码完全不可读,我似乎想不出您正常执行此操作的单一原因。
【解决方案4】:

初始化按照它在类中出现的顺序进行。所以这就是这里发生的事情:

  1. A 已初始化。它开始设置 A.a 但需要 B,所以...
  2. B 已初始化。 B.b 已设置 - A.c 有效但尚未初始化,因此为 0。B.b 变为 2。
  3. A.a 设置为 B.b (2) + c(尚未设置 - 所以为 0)。 A.a 现在是 2。
  4. 最后,c 设置为 3。

【讨论】:

  • 这就是我在编辑/第二次测试后的假设。我不喜欢这个主意。我宁愿得到一个编译错误:x
【解决方案5】:

-edit- 我知道我使用的是静态的,但请解释一下非静态的。我将在一分钟内使用非静态测试

非静态字段不存在这个问题,因为您无法读取尚未构造的对象的实例字段。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-14
    • 1970-01-01
    相关资源
    最近更新 更多