Tom*_*ter 7 c# static static-initializer
我已经阅读了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");
}
Run Code Online (Sandbox Code Playgroud)
输出是:
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
Run Code Online (Sandbox Code Playgroud)
这正是我所期望的输出.特别要注意的是,即使方法F()正在使用参数"Init AU"执行,一旦遇到对BY的引用,它就会被再次调用(如果您愿意,则会中断),从而导致B的静态初始化程序执行.一旦B的静态构造函数完成,我们再次返回到F()的AU调用,它将BY设置为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
Run Code Online (Sandbox Code Playgroud)
C#Spec(v5.0)的第10.5.5.1节和第10.12节表示当引用"类的任何静态成员"时,将触发A的静态构造函数(及其静态初始化程序)执行.然而,我们在F()中引用了AX,并且没有触发A的静态构造函数(因为它的静态初始化器没有运行).
由于A有一个静态构造函数,我希望那些初始化程序运行(并中断)对F()的"Init BR"调用,就像B的静态构造函数在我展示的"Init AU"调用中中断A对F()的调用一样在开始.
谁能解释一下?Af面值看起来违反规范,除非规范的其他部分允许这样做.
谢谢
我想我明白这里发生了什么,尽管我没有很好的解释为什么会这样。
测试程序有点太粗糙,无法看出发生了什么。让我们做一个小调整:
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");
}
Run Code Online (Sandbox Code Playgroud)
输出与问题中的输出类似,但有更多细节:
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
Run Code Online (Sandbox Code Playgroud)
这里没什么奇怪的。删除 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
Run Code Online (Sandbox Code Playgroud)
现在这很有趣。我们可以看到原始输出具有误导性。我们实际上是从尝试初始化开始的A.U。这并不奇怪,因为 A 应该首先初始化,因为A.X它是在 Main 中访问的。下一部分很有趣。看起来,当 B 没有静态构造函数时,CLR 会在进入方法之前FInternal中断将要访问 B 的字段 ( )的方法。将此与其他情况进行对比。B 的初始化被延迟,直到我们实际访问 B 的字段。
我不完全确定为什么事情会按照这个特定的顺序完成,但是您可以看到 B 的初始化没有被中断以初始化 A 的原因是 A 的初始化已经开始。
| 归档时间: |
|
| 查看次数: |
288 次 |
| 最近记录: |