gpt4 book ai didi

具有(和不具有)混合静态构造函数的 C# 静态初始化器

转载 作者:太空狗 更新时间:2023-10-29 20:36:21 25 4
gpt4 key购买 nike

我已经阅读了 C# 语言规范 (v5.0) 的相关部分,但找不到与我所看到的相关的部分。

如果您运行下面的代码,您将看到下面的输出,这正是我所期望的:

using System;

class Test {
static int count = 0;
static void Main() {
Console.WriteLine("In Main(), A.X=" + A.X);
}

public static int F(string message) {
Console.WriteLine(message);
A.X = ++count;

Console.WriteLine("\tA.X has been set to " + A.X);
B.Y = ++count;

Console.WriteLine("\tB.Y has been set to " + B.Y);
return 999;
}
}
class A {
static A() { }
public static int U = Test.F("Init A.U");
public static int X = Test.F("Init A.X");
}

class B {
static B() { }
public static int R = Test.F("Init B.R");
public static int Y = Test.F("Init B.Y");
}

输出是:

Init A.U
A.X has been set to 1
Init B.R
A.X has been set to 3
B.Y has been set to 4
Init B.Y
A.X has been set to 5
B.Y has been set to 6
B.Y has been set to 2
Init A.X
A.X has been set to 7
B.Y has been set to 8
In Main(), A.X=999

这正是我所期望的输出。特别要注意,即使方法 F() 是使用参数“Init A.U”执行的,一旦遇到对 B.Y 的引用,它就会再次调用(如果您愿意,可以中断),从而导致 B 的静态初始化程序执行。一旦 B 的静态构造函数完成,我们再次返回到 A.U 对 F() 的调用,这说明 B.Y 被设置为 6,然后设置为 2。因此,希望这个输出对每个人都有意义。

这是我不理解的地方:如果您注释掉 B 的静态构造函数,您将看到以下输出:

Init B.R
A.X has been set to 1
B.Y has been set to 2
Init B.Y
A.X has been set to 3
B.Y has been set to 4
Init A.U
A.X has been set to 5
B.Y has been set to 6
Init A.X
A.X has been set to 7
B.Y has been set to 8
In Main(), A.X=999

C# 规范 (v5.0) 的第 10.5.5.1 节和第 10.12 节指出,当“引用类的任何静态成员”时,A 的静态构造函数(及其静态初始值设定项)将被触发执行。然而,在这里我们从 F() 中引用了 A.X,并且 A 的静态构造函数被触发(因为它的静态初始值设定项未运行)。

因为 A 有一个静态构造函数,我希望这些初始化器运行(并中断)对 F() 的“Init B.R”调用,就像 B 的静态构造函数在“Init A.U”调用中中断 A 对 F() 的调用一样我在开头展示的。

谁能解释一下?从表面上看,这似乎违反了规范,除非规范的其他部分允许这样做。

谢谢

最佳答案

我想我明白这里发生了什么,尽管我没有很好的解释为什么会这样。

测试程序有点太粗糙,看不出发生了什么。让我们做一个小调整:

class Test {
static int count = 0;
static void Main() {
Console.WriteLine("In Main(), A.X=" + A.X);
}

public static int F(string message) {
Console.WriteLine("Before " + message);
return FInternal(message);
}

private static int FInternal(string message) {
Console.WriteLine("Inside " + message);
A.X = ++count;

Console.WriteLine("\tA.X has been set to " + A.X);
B.Y = ++count;

Console.WriteLine("\tB.Y has been set to " + B.Y);
return 999;
}
}
class A {
static A() { }
public static int U = Test.F("Init A.U");
public static int X = Test.F("Init A.X");
}

class B {
static B() { }
public static int R = Test.F("Init B.R");
public static int Y = Test.F("Init B.Y");
}

输出与问题中的类似,但更详细:

Before Init A.U  
Inside Init A.U
A.X has been set to 1
Before Init B.R
Inside Init B.R
A.X has been set to 3
B.Y has been set to 4
Before Init B.Y
Inside Init B.Y
A.X has been set to 5
B.Y has been set to 6
B.Y has been set to 2
Before Init A.X
Inside Init A.X
A.X has been set to 7
B.Y has been set to 8
In Main(), A.X=999

这里没有什么奇怪的。删除 B 的静态构造函数,这就是你得到的:

Before Init A.U  
Before Init B.R
Inside Init B.R
A.X has been set to 1
B.Y has been set to 2
Before Init B.Y
Inside Init B.Y
A.X has been set to 3
B.Y has been set to 4
Inside Init A.U
A.X has been set to 5
B.Y has been set to 6
Before Init A.X
Inside Init A.X
A.X has been set to 7
B.Y has been set to 8
In Main(), A.X=999

这很有趣。我们可以看到原始输出具有误导性。我们实际上是从尝试初始化 A.U 开始的。这并不奇怪,因为 A 应该首先初始化,因为 A.X 是在 Main 中访问的。下一部分很有趣。看起来当 B 没有静态构造函数时,CLR 会在进入方法之前中断将要访问 B 的字段 (FInternal) 的方法。。将此与另一种情况进行对比。 B 的初始化被延迟到我们实际访问 B 的字段。

我不完全确定为什么事情会以这种特定顺序完成,但你可以看到 B 的初始化没有被中断以初始化 A 的原因是 A 的初始化已经开始。

关于具有(和不具有)混合静态构造函数的 C# 静态初始化器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29710977/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com