Есть одна вещь, которая меня всегда интересовала в отношении static fields
/ constructors
.
static class
инициализируется при первой ссылке на одно из его полей, это легко.
Но как CLR узнает, что это первый раз?
Есть одна вещь, которая меня всегда интересовала в отношении static fields
/ constructors
.
static class
инициализируется при первой ссылке на одно из его полей, это легко.
Но как CLR узнает, что это первый раз?
CLR поддерживает таблицу всех загруженных типов и состояния их инициализации. Если A
использует статическое поле B
, CLR знает, что A
использует B
, и при инициализации A
она также инициализирует B
. Таким образом, проверка инициализации зависимостей не выполняется при каждом доступе. Это обеспечивается графом зависимостей типов.
Если вас интересуют подробности реализации, вы можете взглянуть на метод IsClassInitialized
для DomainLocalModule
в CoreCLR и его использование при создании экземпляров классов.
Надеюсь, это ответит на ваш вопрос.
static class
инициализируется при первой ссылке на одно из его полей, это легко.
Нет, это не так просто. Игнорируя вызовы методов, класс static
должен быть инициализирован непосредственно перед первым доступом к одному из его полей, если он не помечен beforefieldinit
. Если он помечен beforefieldinit
, его можно инициализировать раньше. (У Джона Скита есть статья с большим количеством дополнительной информации о beforefieldinit
.)
Как это влияет на проверку инициализации класса? Поскольку CLR использует JIT-компиляцию, она проверяет инициализацию класса при JIT-компиляции метода. Если класс помечен beforefieldinit
и он еще не инициализирован, JIT-компилятор сразу его инициализирует. Затем он фактически компилирует метод, где он может предположить, что класс уже инициализирован, поэтому никаких проверок не требуется.
Без beforefieldinit
, если класс еще не инициализирован, JIT-компилятор должен выдать код, проверяющий инициализацию перед каждым потенциальным доступом к первому полю. Но если класс уже инициализирован и выполняется JIT-компиляция другого метода, JIT-компилятору больше не нужно выдавать там проверки.
В некоторых случаях это может негативно сказаться на производительности. Из вышеизложенного понятно, что для защиты от этого нужно убедиться, что проблемные классы помечены beforefieldinit
. И способ сделать это из C# - не иметь конструктора static
, использовать только инициализаторы полей static
.