Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
| Свойство | Значение |
|---|---|
| Идентификатор правила | CA1810 |
| Заголовок | Инициализируйте статические поля ссылочных типов встроенным образом |
| Категория | Производительность |
| Исправление является критическим или не критическим | неразрывный |
| Включен по умолчанию в .NET 10 | Нет |
| Применимые языки | C# и Visual Basic |
Причина
Ссылочный тип объявляет явный статический конструктор.
Описание правила
Если в типе объявляется явный статический конструктор, компилятор 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("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("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