2016-03-11 11 views
1

Есть одна вещь, о которой я всегда интересовался static fields/constructors.Как известно CLR, если статическое поле уже было инициализировано?

static class Инициализировано в первый раз, когда упоминается одно из его полей, это легко.

Но как CLR знает, что это первый раз?

ответ

3

CLR поддерживает таблицу всех типов, которые были загружены, и их статус инициализации. Если A использует статическое поле B, то CLR знает, что A использует B, а при инициализации A он также инициализирует B. Таким образом, проверка инициализации зависимостей не выполняется при каждом доступе. Это обеспечивается хотя и графиком зависимостей типов.

Если вы заинтересованы в деталях реализации вы можете посмотреть на IsClassInitialized способе DomainLocalModule в CoreCLR и его usage когда экземпляры классов созданы.

Надеюсь, это ответит на ваш вопрос.

+0

Да, спасибо большое. Хотя я должен признать, что это кажется дорогостоящим проверять каждый раз при доступе к полю (например, в сравнении с C++) –

+0

Чтобы быть понятным, эта проверка не выполняется при каждом доступе к классу. Состояние загрузки класса проверяется при загрузке класса. Если ваш класс A использует статическое свойство B.foo, то при использовании A его зависимости проверяются. Поэтому, когда инициализируется A, B также будет инициализирован. доступ к B.foo не дает таких проверок. – Kolja

+0

Я сделал некоторые изменения для ответа, чтобы сделать его более понятным, когда эта проверка происходит. – Kolja

2

static class Инициализировано в первый раз, когда упоминается одно из его полей, это легко.

Нет, все не так просто. Игнорируя вызовы методов, класс static должен быть инициализирован непосредственно перед тем, как одно из его полей будет доступно в первый раз, если оно не отмечено beforefieldinit. Если он отмечен beforefieldinit, он может быть инициализирован раньше этого. (У Jon Skeet есть an article with lots more information about beforefieldinit.)

Как это влияет на проверку инициализации класса? Поскольку CLR использует компиляцию JIT, она проверяет инициализацию класса при компиляции метода JIT. Если класс помечен beforefieldinit, и он еще не был инициализирован, компилятор JIT инициализирует его сразу. Затем он фактически компилирует метод, где он может предположить, что класс уже инициализирован, поэтому никаких проверок не требуется.

Без beforefieldinit, если класс еще не был инициализирован, компилятор JIT должен испускать код, который проверяет инициализацию перед каждым потенциальным первым доступом к полю. Но если класс уже инициализирован, а другой метод скомпилирован JIT, компилятор JIT больше не должен выставлять чеки.

Это может негативно отразиться на производительности в некоторых случаях. Из вышесказанного ясно, что для защиты от этого вам необходимо убедиться, что проблемные классы отмечены beforefieldinit. И способ сделать это из C# - не иметь конструктора static, используйте только инициализаторы полей static.

+0

Интересно.Думаю, это было бы особенно проблематично, если бы потенциальный первый доступ к полю был разбросан по всему решению и сильно зависит от внешнего входа. Определенно благодарю вас за подробный ответ. –