CA1810: инициализируйте статические поля ссылочного типа встроенными средствами
Свойство | Значение |
---|---|
Идентификатор правила | CA1810 |
Заголовок | Инициализируйте статические поля ссылочных типов при объявлении |
Категория | Производительность |
Исправление является критическим или не критическим | Не критическое |
Включен по умолчанию в .NET 8 | No |
Причина
Ссылочный тип объявляет явный статический конструктор.
Описание правила
Если в типе объявляется явный статический конструктор, компилятор JIT добавляет проверку в каждый статический метод и конструктор экземпляров этого типа, чтобы убедиться, что статический конструктор уже вызывался ранее. Статическая инициализация активируется при доступе к любому статическому элементу или при создании экземпляра типа. Однако статическая инициализация не запускается, если объявить переменную типа, но не использовать ее, что может быть важно, если инициализация меняет глобальное состояние.
Если все статические данные инициализированы встроенными и явным статическим конструктором не объявлены, компиляторы общего промежуточного языка (CIL) добавляют beforefieldinit
флаг и неявный статический конструктор, который инициализирует статические данные в определение типа CIL. Когда JIT-компилятор обнаруживает флаг beforefieldinit
, в большинстве случаев проверки статических конструкторов не добавляются. Статическая инициализация будет гарантированно выполняться в определенный момент перед обращением к статическим полям, но не до вызова статического метода или конструктора экземпляра. Обратите внимание, что статическая инициализация может произойти в любое время после объявления переменной типа.
Проверки статических конструкторов могут привести к снижению производительности. Часто статический конструктор используется только для инициализации статических полей. В этом случае необходимо лишь убедиться, что статическая инициализация выполняется перед первым доступом к статическому полю. Поведение beforefieldinit
подходит для этих и большинства других типов. Оно неприемлемо, только если статическая инициализация влияет на глобальное состояние, и одно из следующих условий верно:
Воздействие на глобальное состояние является дорогостоящим и не требуется, если тип не используется.
Доступ к эффектам глобального состояния возможен без доступа к любым статическим полям типа.
Устранение нарушений
Чтобы устранить нарушение данного правила, выполните инициализацию всех статических данных при их объявлении и удалите статический конструктор.
Когда лучше отключить предупреждения
Если применяется одно из следующих действий, можно отключить предупреждение из этого правила:
- Производительность не является проблемой.
- Глобальные изменения состояния, вызванные статической инициализацией, являются дорогостоящими или должны быть гарантированы до вызова статического метода типа или создания экземпляра типа.
Отключение предупреждений
Если вы просто хотите отключить одно нарушение, добавьте директивы препроцессора в исходный файл, чтобы отключить и повторно включить правило.
#pragma warning disable CA1810
// The code that's violating the rule is on this line.
#pragma warning restore CA1810
Чтобы отключить правило для файла, папки или проекта, задайте его серьезность none
в файле конфигурации.
[*.{cs,vb}]
dotnet_diagnostic.CA1810.severity = none
Дополнительные сведения см. в разделе Практическое руководство. Скрытие предупреждений анализа кода.
Пример
В следующем примере показаны тип StaticConstructor
, который нарушает правило, и тип NoStaticConstructor
, который заменяет статический конструктор встроенной инициализацией для выполнения этого правила.
public class StaticConstructor
{
static int someInteger;
static string? resourceString;
static StaticConstructor()
{
someInteger = 3;
ResourceManager stringManager =
new ResourceManager("strings", Assembly.GetExecutingAssembly());
resourceString = stringManager.GetString("string");
}
public void Print()
{
Console.WriteLine(someInteger);
}
}
public class NoStaticConstructor
{
static int someInteger = 3;
static string? resourceString = InitializeResourceString();
static string? InitializeResourceString()
{
ResourceManager stringManager =
new ResourceManager("strings", Assembly.GetExecutingAssembly());
return stringManager.GetString("string");
}
public void Print()
{
Console.WriteLine(someInteger);
}
}
Imports System
Imports System.Resources
Namespace ca1810
Public Class StaticConstructor
Shared someInteger As Integer
Shared resourceString As String
Shared Sub New()
someInteger = 3
Dim stringManager As New ResourceManager("strings",
System.Reflection.Assembly.GetExecutingAssembly())
resourceString = stringManager.GetString("string")
End Sub
End Class
Public Class NoStaticConstructor
Shared someInteger As Integer = 3
Shared resourceString As String = InitializeResourceString()
Private Shared Function InitializeResourceString()
Dim stringManager As New ResourceManager("strings",
System.Reflection.Assembly.GetExecutingAssembly())
Return stringManager.GetString("string")
End Function
End Class
End Namespace
Обратите внимание на добавление флага beforefieldinit
в определение CIL для NoStaticConstructor
класса.
.class public auto ansi StaticConstructor
extends [mscorlib]System.Object
{
} // end of class StaticConstructor
.class public auto ansi beforefieldinit NoStaticConstructor
extends [mscorlib]System.Object
{
} // end of class NoStaticConstructor