Я просмотрел соответствующий раздел Спецификации языка С# (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
В разделах 10.5.5.1 и 10.12 C# Spec (v5.0) указано, что статический конструктор A (и его статические инициализаторы) запускается для выполнения, когда «ссылаются на любой из статических членов класса». Однако здесь мы имеем ссылку на A.X из F(), а статический конструктор A не запускается (поскольку его статические инициализаторы не запущены).
Поскольку A имеет статический конструктор, я ожидаю, что эти инициализаторы будут запускать (и прерывать) вызов «Init BR» для F(), точно так же, как статический конструктор B прервал вызов A для F() в вызове «Init AU», который я показал с начала.
Кто-нибудь может объяснить? На первый взгляд это выглядит как нарушение спецификации, если только это не допускается какой-либо другой частью спецификации.
Спасибо
Test.F
требует загрузки информации о типе B. - person Mike Zboray   schedule 18.04.2015