CA1810: Statische Felder von Referenztypen inline initialisieren.

Eigenschaft Wert
Regel-ID CA1810
Titel Statische Felder von Referenztypen inline initialisieren.
Kategorie Leistung
Fix führt oder führt nicht zur Unterbrechung Nicht unterbrechend
Standardmäßig in .NET 9 aktiviert No

Ursache

Ein Referenztyp deklariert einen expliziten statischen Konstruktor.

Regelbeschreibung

Wenn ein Typ einen expliziten statischen Konstruktor deklariert, überprüft der JIT-Compiler (Just in Time) jede statische Methode und jeden Instanzenkonstruktor des Typs. Dadurch wird sichergestellt, dass der statische Konstruktor zuvor aufgerufen wurde. Die statische Initialisierung wird ausgelöst, wenn auf einen statischen Member zugegriffen wird oder wenn eine Instanz des Typs erstellt wird. Die statische Initialisierung wird jedoch nicht ausgelöst, wenn Sie eine Variable des Typs deklarieren, aber nicht verwenden. Dies kann wichtig sein, wenn die Initialisierung den globalen Zustand ändert.

Wenn alle statischen Daten inline initialisiert werden und kein expliziter statischer Konstruktor deklariert wird, fügen gängige CIL-Compiler das beforefieldinit Flag und einen impliziten statischen Konstruktor hinzu, der die statischen Daten initialisiert, zur CIL-Typdefinition. Wenn der JIT-Compiler auf die beforefieldinit-Kennzeichnung trifft, werden die statischen Konstruktorüberprüfungen meistens nicht hinzugefügt. Die statische Initialisierung wird garantiert zu einem bestimmten Zeitpunkt ausgeführt, bevor auf statische Felder zugegriffen wird, jedoch nicht, bevor eine statische Methode oder ein Instanzkonstruktor aufgerufen wird. Beachten Sie, dass die statische Initialisierung jederzeit erfolgen kann, nachdem eine Variable vom Typ deklariert wurde.

Durch die Überprüfung statischer Konstruktoren kann die Leistung herabgesetzt werden. Häufig wird ein statischer Konstruktor nur zum Initialisieren statischer Felder verwendet. In diesem Fall müssen Sie nur sicherstellen, dass die statische Initialisierung vor dem ersten Zugriff eines statischen Felds erfolgt. Das beforefieldinit-Verhalten ist für diese und die meisten anderen Typen geeignet. Sie ist nur ungeeignet, wenn die statische Initialisierung den globalen Zustand beeinflusst und eine der folgenden Punkte zutrifft:

  • Die Auswirkung auf den globalen Status ist aufwendig und ist nicht erforderlich, wenn der Typ nicht verwendet wird.

  • Auf die globalen Zustandseffekte kann ohne Zugriff auf statische Felder des Typs zugegriffen werden.

Behandeln von Verstößen

Um einen Verstoß gegen diese Regel zu beheben, initialisieren Sie alle statischen Daten nach deren Deklaration und entfernen den statischen Konstruktor.

Wann sollten Warnungen unterdrückt werden?

In den folgenden Fällen können durch diese Regel ausgelöste Warnungen ohne Risiko unterdrückt werden:

  • Die Leistung spielt keine Rolle.
  • Globale Zustandsänderungen, die durch eine statische Initialisierung verursacht werden, sind teuer oder müssen garantiert werden, bevor eine statische Methode des Typs aufgerufen oder eine Instanz des Typs erstellt wird.

Unterdrücken einer Warnung

Um nur eine einzelne Verletzung zu unterdrücken, fügen Sie der Quelldatei Präprozessoranweisungen hinzu, um die Regel zu deaktivieren und dann wieder zu aktivieren.

#pragma warning disable CA1810
// The code that's violating the rule is on this line.
#pragma warning restore CA1810

Um die Regel für eine Datei, einen Ordner oder ein Projekt zu deaktivieren, legen Sie den Schweregrad in der Konfigurationsdatei auf none fest.

[*.{cs,vb}]
dotnet_diagnostic.CA1810.severity = none

Weitere Informationen finden Sie unter Vorgehensweise: Unterdrücken von Codeanalyse-Warnungen.

Beispiel

Das folgende Beispiel zeigt einen Typ, StaticConstructor, der gegen die Regel verstößt, und einen Typ, NoStaticConstructor, der den statischen Konstruktor durch Inline-Initialisierung ersetzt, um die Regel zu erfüllen.

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

Beachten Sie das Hinzufügen des beforefieldinit Flags in der CIL-Definition für die NoStaticConstructor Klasse.

.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