Що робить прапор beforefieldinit?


82

Що робить прапор beforefieldinit? Коли я заглядаю в ІЛ свого класу, то бачу цей прапор, але не знаю, що насправді робить цей прапор?

Відповіді:


132

Дивіться мою статтю саме з цього питання.

По суті, beforefieldinitозначає "тип може бути ініціалізований у будь-який момент до посилання на будь-які статичні поля". Теоретично це означає, що його можна дуже лінько ініціалізувати - якщо ви викликаєте статичний метод, який не торкається жодного поля, JIT не потрібно ініціалізувати тип.

На практиці це означає, що клас ініціалізується раніше, ніж це було б інакше - це нормально, якщо він ініціалізується на початку першого методу, який міг би його використовувати. Порівняйте це з типами , які НЕ були beforefieldinitзастосовані до них, коли ініціалізації типу повинна відбуватися безпосередньо перед першим фактичним використанням.

Отже, припустимо, що ми маємо:

public static void DoSomething(bool which)
{
    if (which)
    {
        FirstType.Foo();
    }
    else
    {
        SecondType.Bar();
    }
}

Якщо обидва типи beforefieldinitзастосували до них (що в C # вони роблять за замовчуванням, якщо тип не має статичного конструктора), тоді обидва вони будуть ініціалізовані на початку DoSomethingметоду (зазвичай - це не гарантовано). Якщо їх немає, beforefieldinitтоді буде ініціалізовано лише один із них на основі прапора.

Ось чому зазвичай застосовується статичний конструктор (навіть порожній!) При реалізації шаблону singleton .


"тип може бути ініціалізований у будь-який момент до посилання на будь-які поля." це справедливо і для запуску статичних методів?
Рої Намір

@RoyiNamir, специфікація CLI говорить, що якщо застосовується BeforeFieldInit, тоді "метод ініціалізатора типу виконується при першому доступі до будь-якого статичного поля, визначеного для цього типу, або десь раніше". Якщо цей атрибут пропущений (static .ctor), тоді "перший доступ до будь-якого поля статики або екземпляра цього типу або перше виклик будь-якого статичного, екземпляра або віртуального методу цього типу". Отже, це не відповідає застосованому BeforeFieldInit, якщо статичний метод не посилається на інше статичне поле.
Арман

3
Я виявив, що за використання статичних конструкторів передбачено покарання за продуктивність (тобто класи, які не мають прапорця beforefieldinit). Якщо ви часто викликаєте статичних членів певного класу, здається, що середовище виконання повинно робити додаткову перевірку перед кожним викликом, щоб перевірити, чи тип ще не ініціалізований; beforefieldinit уникає цих перевірок. Пара тестів була приблизно на 50% швидшою за допомогою beforefieldinit
Qwertie,

6

Схоже, це зміниться в 4.6

https://github.com/dotnet/coreclr/issues/1193


Чудово, так чи означає це, що він буде чекати до останнього моменту, щоб ініціалізувати поле (незалежно від того, є воно beforefieldinitчи ні)?
James Ko

1
Перед першим використанням усі звернення матимуть префікс перевірки ініціалізації. Після цього, коли інші методи будуть змінені, згенерований код буде безпосередньо отримувати доступ до поля. Якщо він примітивного типу, тоді його навіть можна використовувати як постійну часу JIT.
OmariO

2
Детальний аналіз Джона щодо змін до ініціалізації типу, починаючи з .Net 4.0 тут .
RBT
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.