CA1810: Zainicjuj wbudowane pola statyczne typu referencyjnego

Właściwości Wartość
Identyfikator reguły CA1810
Tytuł Inicjuj pola statyczne typu referencyjnego śródwierszowo
Kategoria Wydajność
Poprawka powodująca niezgodność lub niezgodność Niezgodność
Domyślnie włączone na platformie .NET 8 Nie.

Przyczyna

Typ odwołania deklaruje jawny konstruktor statyczny.

Opis reguły

Podczas gdy typ deklaruje jawny, statyczny konstruktor, kompilator just in time (JIT) do każdej metody statycznej dodaje sprawdzenie i konstruktora wystąpienia, aby upewnić się, że konstruktor statyczny został wcześniej wywołany. Inicjowanie statyczne jest wyzwalane, gdy dowolny statyczny element członkowski jest uzyskiwany lub gdy tworzone jest wystąpienie typu. Jednak inicjowanie statyczne nie jest wyzwalane, jeśli deklarujesz zmienną typu, ale nie używasz jej, co może być ważne, jeśli inicjowanie zmieni stan globalny.

Gdy wszystkie dane statyczne są inicjowane w tekście i jawny konstruktor statyczny nie jest zadeklarowany, kompilatory wspólnego języka pośredniego (CIL) dodają flagę beforefieldinit i niejawny konstruktor statyczny, który inicjuje dane statyczne do definicji typu CIL. Gdy kompilator JIT napotka flagę beforefieldinit , większość czasu sprawdzania konstruktora statycznego nie jest dodawana. Inicjowanie statyczne jest gwarantowane w pewnym momencie przed uzyskaniem dostępu do wszystkich pól statycznych, ale nie przed wywołaniem metody statycznej lub konstruktora wystąpienia. Należy pamiętać, że inicjowanie statyczne może wystąpić w dowolnym momencie po zadeklarowaniu zmiennej typu.

Sprawdzenia konstruktora statycznego mogą obniżyć wydajność. Często statyczny konstruktor jest używany tylko do inicjowania pól statycznych. W takim przypadku należy tylko upewnić się, że inicjowanie statyczne ma miejsce przed pierwszym dostępem do pola statycznego. Zachowanie beforefieldinit jest odpowiednie dla tych i większości innych typów. Jest to nieodpowiednie tylko wtedy, gdy inicjowanie statyczne wpływa na stan globalny, a jedna z następujących wartości jest prawdziwa:

  • Wpływ na stan globalny jest kosztowny i nie jest wymagany, jeśli typ nie jest używany.

  • Dostęp do globalnych efektów stanu można uzyskać bez uzyskiwania dostępu do jakichkolwiek pól statycznych typu.

Jak naprawić naruszenia

Aby naprawić naruszenie tej zasady, zainicjuj wszystkie dane statyczne, gdy jest on zadeklarowany, i usuń konstruktor statyczny.

Kiedy pomijać ostrzeżenia

Można bezpiecznie pominąć ostrzeżenie z tej reguły, jeśli ma zastosowanie jedno z następujących elementów:

  • Wydajność nie jest problemem.
  • Globalne zmiany stanu spowodowane przez inicjowanie statyczne są kosztowne lub muszą być gwarantowane przed wywołaniem statycznej metody typu lub utworzeniem wystąpienia typu.

Pomijanie ostrzeżenia

Jeśli chcesz po prostu pominąć pojedyncze naruszenie, dodaj dyrektywy preprocesora do pliku źródłowego, aby wyłączyć, a następnie ponownie włączyć regułę.

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

Aby wyłączyć regułę dla pliku, folderu lub projektu, ustaw jego ważność na none w pliku konfiguracji.

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

Aby uzyskać więcej informacji, zobacz Jak pominąć ostrzeżenia dotyczące analizy kodu.

Przykład

W poniższym przykładzie pokazano typ , StaticConstructorktóry narusza regułę i typ , NoStaticConstructorktóry zastępuje konstruktor statyczny inline inicjalizacji, aby spełnić regułę.

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

Zwróć uwagę na beforefieldinit dodanie flagi w definicji CIL dla NoStaticConstructor klasy.

.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