Порядок инициализации статического члена в одном классе C#

Рассмотрим следующий фрагмент класса с двумя статическими переменными-членами:

            public static class Foo
            {

                static string A = GetA(B);
                static string B = "required for A";
                ...

Насколько я понимаю, A и B будут инициализированы при первом доступе к ним. Однако, когда я выполнил полностью реализованную версию фрагмента выше, где A был доступен до инициализации B, это привело к тому, что null было передано в GetA() вместо "required for A". Почему поведение не начинается с инициализации A, а затем, когда выясняется, что B требуется для инициализации A, инициализируется B, а затем возвращается, чтобы завершить инициализацию A?

Каковы общие правила по этому поводу? Почему оно так себя ведет? Я видел другие вопросы, касающиеся этого (Когда статические переменные получают инициализированы в C#?), но они не дают точного ответа на этот вопрос. Каков порядок инициализации статических переменных в C#? в первую очередь рассказывает о том, как это работает между классами, а не внутри одного класса (хотя дополнение Джона Скита к его ответу - "По многочисленным просьбам, вот мой первоначальный ответ, когда я думал, что вопрос был об инициализации порядок статических переменных в классе:...." действительно отвечает на этот вопрос, он скрыт в гораздо более длинном ответе).


person Adam    schedule 27.03.2019    source источник
comment
@ Алексей Левенков, посмотрите мое редактирование, почему я думаю, что этот вопрос следует рассматривать отдельно от того, на который вы ссылаетесь. По сути, хотя ответ на мой вопрос скрыт в ответе Джона Скита на вопрос, который вы связали, связанный вопрос в первую очередь касается того, как это работает в разных классах, а не в одном классе.   -  person Adam    schedule 27.03.2019


Ответы (1)


Короче, не делай этого.

Стандартная спецификация языка C# ECMA-334

15.5.6.2 Инициализация статического поля

Инициализаторы переменных статического поля класса соответствуют последовательности назначений, которые выполняются в текстовом порядке, в котором они появляются в объявлении класса (§15.5.6.1). В частичном классе значение «текстового порядка» определяется §15.5.6.1. Если в классе существует статический конструктор (§15.12), выполнение инициализаторов статического поля происходит непосредственно перед выполнением этого статического конструктора. В противном случае инициализаторы статического поля выполняются во время, зависящее от реализации, до первого использования статического поля этого класса

Исправление:

  • Расположите их по порядку и используйте Статический конструктор,
  • или просто инициализируйте их в статическом конструкторе, что, в свою очередь, даст вам возможность управлять порядком инициализации (учитывая приведенную выше информацию).

Лично я предлагаю инициализировать их в статическом конструкторе, это, кажется, делает его более конкретным и понятным и с меньшей вероятностью будет сталкиваться с рефакторингом.

person TheGeneral    schedule 27.03.2019
comment
ОК, я понимаю, что обычно вещи выполняются в текстовом порядке, в котором они появляются. Но что произойдет, если инициализация одного статического поля зависит от значения другого? Изменяет ли это порядок инициализации, т. е. требуемое статическое поле будет инициализировано первым? Мой пример показывает, что это не так... - person Adam; 27.03.2019
comment
В общем, я до сих пор в замешательстве. Инициализируются ли статические поля в текстовом порядке или это зависит от того, к каким полям обращаются первыми? - person Adam; 27.03.2019
comment
Глядя на ваш ответ и ответ Джона Скита на вопрос, связанный с Алексеем Левенковым, я думаю, что это ответ: внутри класса статические члены инициализируются в текстовом порядке. между классами это немного сложнее, но в двух словах. Если выражение инициализации для статической переменной требует инициализации другого типа, то этот другой тип будет полностью инициализирован до присвоения значения переменной - если только этот второй тип уже инициализируется (из-за циклической зависимости). Я считаю, что типы здесь являются синонимом классов. - person Adam; 27.03.2019
comment
@Adam да, ответы Джона намного точнее, однако предпосылка заключалась в том, что у вас есть нулевая проблема, состоящая в том, чтобы инициализировать их в конструкторе, где у вас есть полный контроль над порядком. Нет сложностей реализации и рефакторинг не нарушит логику. Это также облегчает понимание того, что происходит и почему. В любом случае да, ваши выводы кажутся почти правильными, удачи - person TheGeneral; 28.03.2019