First
начнет инициализацию, назначит firstArray
, затем заметит, что требуется инициализация Second
, чтобы получить начальное значение secondArray
. * Запустится
Second
инициализировать, а затем заметить, что требуется сначала инициализировать.Однако CLR затем заметит, что First * уже инициализируется в текущем потоке, поэтому он не блокируется.Инициализация Second
завершится, а затем завершится инициализация First.
К счастью, поле, в котором нуждается Second
, уже назначено, так что происходит "правильная вещь".Это очень хорошо, если First
на самом деле начинает инициализацию первой.Тем не менее, поскольку ни один из классов не имеет статического конструктора, возможно, что Second
начнет сначала инициализироваться ... затем начнется инициализация First
, что определит, что Second
уже инициализируется, и примет Second.secondArray
текущее значение (ноль) для First.secondArray
.Это было бы плохо.Обратите внимание, что время инициализации для типов без статических конструкторов изменилось в *. 1024 * в .NET 4 - не с нарушением спецификации, но, возможно, с существующим нарушением кода.
Если обаFirst
и Second
имеют статические конструкторы, затем сначала инициализируется First
, поскольку это первый класс, которого касается Main
.
Мораль ответа: не делайте этого.Инициализаторы типов, которые ссылаются друг на друга, очень подвержены ошибкам.Другой пример - см. Выступление Эрика Липперта и Нила Гафтера в NDC 2010, «C # Puzzlers», которое можно посмотреть на странице NDC .
.