Пару дней назад я спросил себя о разнице, если таковая имеется, между инициализацией статических полей через статический конструктор и выполнением этого с помощью инициализатора статического поля (встроенная инициализация статического поля в точке объявления).
После прочтения множества вопросов stackoverflow на эту тему и знаменитой статьи Джона Скита о флаге beforefieldinit я теперь мы гораздо лучше понимаем разницу между двумя стратегиями инициализации.
Есть один момент, в котором я не уверен, в основном потому, что я не смог найти никакой официальной документации по этому поводу.
Статический конструктор гарантированно выполняется только один раз, и я думаю, что это верно даже в сценариях с несколькими потоками (когда разные потоки создают экземпляры класса и/или используют статические члены класса. В любом случае, статический конструктор запускается один и только один раз).
Верно ли это даже для встроенной инициализации статических полей? Гарантируется ли однократное выполнение встроенной инициализации статического поля даже в многопоточных сценариях?
Еще один момент, который я все еще упускаю, это то, каковы практические последствия этой разницы в инициализации статических полей класса. Другими словами, я хотел бы понять, когда на правильность фрагмента кода может повлиять выбор инициализации статического встроенного поля в точке объявления (вместо использования статического конструктора).
Большую часть времени (в основном это зависит от типа кода, над которым я обычно работаю, а именно от веб-приложений) я использую статические поля только для чтения в классах обслуживания для хранения вещей, которые используются службой, которую я пишу, для выполнения вычислений или принятия решений. . Я решил поместить эти вещи в статические поля, потому что они должны быть одинаковыми для всех возможных экземпляров класса, который я пишу, на самом деле они являются инвариантами, которые не принадлежат конкретному экземпляру, но вместо этого они принадлежат самому алгоритму.
Вот пример:
public class SomeInterestingService
{
private static readonly int ConstantNumber = 13;
private static readonly string[] Names = new[] { "bob", "alice" };
private readonly INumberGenerator numberGenerator;
public SomeInterestingService(INumberGenerator numberGenerator)
{
this.numberGenerator = numberGenerator ?? throw new ArgumenNullException(nameof(numberGenerator));
}
public int ComputeMagicNumber()
{
int answer = this.numberGenerator.GetNumber();
foreach(var name in names)
{
answer += name.Length;
}
answer += ConstantNumber;
return answer;
}
}
Есть ли в таком коде какая-либо практическая разница в выборе инициализации статического конструктора или встроенной инициализации статических полей ConstantNumber
и Names
, помимо разницы в производительности (встроенная инициализация более эффективна из-за оптимизации во время выполнения, которая невозможна при использовании статического конструктор) ?
Может ли правильность приведенного выше кода быть затронута coiche в каком-либо странном угловом случае? (Думаю, нет)
readonly
делает вопрос довольно академическим — ConstantNumber всегда будет 13, даже если инициализация выполнялась дважды. Но теоретически Алису и Боба можно заменить. - person Henk Holterman   schedule 16.11.2019