CA1810:参照型の静的フィールドをインラインで初期化します

プロパティ
ルール ID CA1810
Title 参照型の静的フィールドをインラインで初期化します
[カテゴリ] パフォーマンス
修正が中断ありか中断なしか なし
.NET 8 では既定で有効 いいえ

原因

参照型で明示的な静的コンストラクターを宣言しています。

規則の説明

型で明示的な静的コンストラクターを宣言すると、Just-In-Time (JIT) コンパイラが、静的コンストラクターが呼び出されたことを確認するために、型の静的メソッドと静的インスタンス コンストラクターに個別にチェックを追加します。 静的な初期化は、静的メンバーへのアクセス時または型のインスタンスの作成時にトリガーされます。 ただし、静的な初期化は、型の変数を宣言しても使用しない場合にはトリガーされません。これは、初期化によってグローバル状態が変更される場合に重要になることがあります。

すべての静的データがインラインで初期化され、明示的な静的コンストラクターが宣言されていない場合、共通中間言語 (CIL) コンパイラはフラグと、静的データを初期化する暗黙的な静的コンストラクターを CIL 型定義に追加 beforefieldinit します。 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