Хорошо, если один тип зависит от инициализируемого другого типа, если только вы не окажетесь в цикле.
В основном это нормально:
public class Child
{
static Child() {} // Added static constructor for extra predictability
public static readonly int X = 10;
}
public class Parent
{
static Parent() {} // Added static constructor for extra predictability
public static readonly int Y = Child.X;
}
Результат четко определен. Инициализаторы статических переменных Child
выполняются до первого доступа к любому статическому полю в классе, согласно разделу 10.5.5.1 спецификации.
Это не так:
public class Child
{
public static readonly int Nasty = Parent.Y;
public static readonly int X = 10;
}
public class Parent
{
public static readonly int Y = Child.X;
}
В этом последнем случае вы либо получите Child.Nasty=0
, Parent.Y=10
, Child.X=10
или Child.Nasty=0
, Parent.Y=0
, Child.X=10
в зависимости от к какому классу обращаются первыми.
При доступе к Parent.Y first
сначала начнется инициализация Parent
, что приведет к инициализации Child
. Инициализация Child
поймет, что Parent
нужно инициализировать, но CLR знает, что она уже инициализируется, поэтому продолжает независимо, приводя к первому набору чисел - потому что Child.X
заканчивается инициализацией до его значение используется для Parent.Y
.
При доступе к Child.Nasty
сначала начнется инициализация Child
, а затем начнется инициализация Parent
. Инициализация Parent
поймет, что Child
нужно инициализировать, но CLR знает, что она уже инициализируется, поэтому продолжает независимо, приводя ко второму набору чисел.
Не делай этого.
РЕДАКТИРОВАТЬ: Хорошо, более подробное объяснение, как и было обещано.
Когда инициализируется тип?
Если тип имеет статический конструктор , он будет только инициализирован
когда он впервые используется (или когда на статический член ссылаются, или
когда экземпляр создан). Если он не имеет статический
конструктор, он может быть инициализирован ранее. В теории это также может
быть инициализирован позже; Вы могли бы теоретически назвать конструктор или
статический метод без инициализации статических переменных - но
он должен быть инициализирован, прежде чем будут ссылаться на статические переменные.
Что происходит во время инициализации?
Во-первых, все статические переменные получают свои значения по умолчанию (0, ноль
и т.д.).
Затем статические переменные типа инициализируются в текстовом
порядок. Если выражение инициализатора для статической переменной требует
другой тип для инициализации, тогда этот другой тип будет
полностью инициализируется до присвоения значения переменной -
, если этот второй тип уже инициализируется (из-за
циклическая зависимость). По сути, тип является либо:
- Уже инициализирован
- Инициализируется в данный момент
- Не инициализировано
Инициализация запускается только в том случае, если тип не инициализирован.
Это означает, что при наличии циклических зависимостей возможно
наблюдать значение статической переменной до того, как ее начальное значение
был назначен . Вот что показывает мой пример Child
/ Parent
.
После выполнения всех инициализаторов статических переменных статические
конструктор выполняет.
Подробнее об этом см. В разделе 10.12 спецификации C #.
По многочисленным просьбам, вот мой первоначальный ответ, когда я подумал, что вопрос касается порядка инициализации статических переменных в классе :
Статические переменные инициализируются в текстовом порядке согласно разделу 10.5.5.1 спецификации C #:
Инициализаторы переменных статического поля
класса соответствуют последовательности
назначения, которые выполняются в
текстовый порядок, в котором они появляются в
объявление класса.
Обратите внимание, что частичные типы усложняют задачу, поскольку нет единого канонического "текстового порядка" класса.