C 语言中的静态构造函数和字段初始化顺序#

Static constructors and field initialization order in C#

提问人:saner 提问时间:2/3/2023 最后编辑:Dmitry Bychenkosaner 更新时间:2/11/2023 访问量:91

问:

简而言之,这个来自 C# 的示例说它写了 0 后跟 3,因为“实例化 Foo 的字段初始值设定项在 X 初始化为 3 之前执行”。

class Program {
  static void Main() { Console.WriteLine (Foo.X); }   // 3
}

class Foo
{
    public static Foo Instance = new Foo(); //static field 1
    public static int X = 3; //static field 2
    
    Foo() => Console.WriteLine (X);   // 0
}

我的问题是,为什么由于静态场 1 产生新的 Foo(产生新的 Foo,产生新的 Foo,等等)而没有进入无限递归?

C# 静态 静态初始化

评论

2赞 pm100 2/3/2023
static 只生成一个 objecvt - 在所有 Foo 实例之间共享

答:

1赞 pigeonhands 2/3/2023 #1

静态字段和属性在类的所有实例之间共享,并在一个名为的特殊构造函数中初始化,该构造函数在首次引用类时被调用。.cctor

所以编译后的代码类似于

class Foo
{
    public static Foo Instance;
    public static int X;
    .cctor() {
        Instance = new Foo();
        X = 3;
    }
    
    Foo() => Console.WriteLine (X);
}

呼叫流为 -> -> 。Foo::.cctorFoo::Foo()Foo:get_X()

因此,没有递归,但在调用时将具有其默认值。X.cctor

1赞 Dmitry Bychenko 2/4/2023 #2

让我们来看看发生了什么。在类寻址字段之前,必须 初始 化。Foostatic

class Program {
  static void Main() { 
    // Before Foo class is addressed (here Foo.X), Foo must be initialized 
    Console.WriteLine(Foo.X); 
  }   
}

.Net 将按照类声明中提及的顺序执行此操作:

class Foo
{
    // Will be run first
    public static Foo Instance = new Foo(); 
    // Will be run second
    public static int X = 3; 
    
    Foo() => Console.WriteLine(X);   
}
  1. 到目前为止一切顺利,开始初始化Instance
public static Foo Instance = new Foo(); 

构造函数调用,打印: 注意, 由于尚未初始化,将被打印。Foo()XFoo() => Console.WriteLine (X);X0

  1. X将被初始化,现在是3

初始化现已完成,.Net 已准备好添加 dress 类Foo

Console.WriteLine(Foo.X); 

并将打印(注意初始化的第二步)3