CA1810:以内联方式初始化引用类型的静态字段

属性
规则 ID CA1810
标题 以内联方式初始化引用类型的静态字段
类别 “性能”
修复是中断修复还是非中断修复 非中断
在 .NET 8 中默认启用

原因

引用类型声明显式静态构造函数。

规则说明

当一个类型声明显式静态构造函数时,实时 (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

请注意在类的 CIL 定义NoStaticConstructor上添加beforefieldinit标志。

.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