【问题标题】:Static field initialization Order in C#C#中的静态字段初始化顺序
【发布时间】:2017-05-31 07:45:15
【问题描述】:

我遇到了 this 链接并找到了下面的 sn-p。我很想尝试 sn-p 以获得不确定的输出。

下面的sn-p:

using System;
class Test
{
   static void Main() 
   {  // Breakpoint here is skipped and control goes to Class B then Class A
      // Why control is always going to Class B first?
      Console.WriteLine("{0} {1}", B.Y, A.X);
   }
   public static int F(string s) {
      Console.WriteLine(s);
      return 1;
   }
}
class A
{       // 
   public static int X = Test.F("Init A");
}
class B
{       // Debugging always starts here.
   public static int Y = Test.F("Init B");
}

可能会产生以下输出:

初始化A

初始化 B

1 1

或输出:

初始化 B

初始化A

1 1

但是,出于某种原因,我总是得到第二个输出。无论我运行/重建/构建多少次。

谁能解释一下:

  1. 为什么只有 B 类首先被执行?如果我将呼叫反转为 'A.X, B.Y',那么只有 A 类首先被执行。
  2. 如何模拟不确定的行为?

【问题讨论】:

  • 如果您只是在同一台机器上针对同一个 CLR 运行,您不太可能看到变化。存在不确定性和灵活性,例如JIT 编译器的不同实现。
  • 如果执行顺序与代码所需的顺序相关,我不会感到惊讶 - 如果不需要,为什么要初始化某些东西。如果您使用“B.Y,B.Y”调用 - 那么我希望 A.X 未初始化。
  • 完整阅读您的链接我看到的措辞是这样的:“否则,静态字段初始化程序在第一次使用该类的静态字段之前在与实现相关的时间执行。 " 和以后的"它们只被限制在引用这些字段之前出现"。所以实际上它的意思是必须在首次使用之前完成初始化并且由实现来决定何时 - 这与说行为不确定并且可能以任何顺序发生是不同的。

标签: c# .net oop clr


【解决方案1】:

为什么只有 B 类首先被执行?

规范说两个输出都是有效的。但是编译器和运行时的特定组合(例如,在 .Net Framework 4.7 上运行的 C# 7.0 编译器)可以决定更加严格并且行为一致。

您使用的组合似乎决定首先初始化首先使用的类的静态字段,并且根据规范这样做是可以接受的。

如何模拟不确定的行为?

同样,规范不需要任何不确定性。

如果您真的想让它这样运行,您可以修改现有的 .Net 运行时(如 CoreCLR、Mono 或 DotNetAnywhere),以找到所有可能的初始化顺序,然后随机选择一个。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-02
    • 2021-07-12
    • 1970-01-01
    • 2015-05-19
    • 2015-06-01
    • 1970-01-01
    • 2014-10-03
    相关资源
    最近更新 更多