Udostępnij za pośrednictwem


CA1810: Zainicjuj pola statyczne typu referencyjnego bezpośrednio

Właściwości Wartość
Identyfikator reguły CA1810
Tytuł Inicjuj statyczne pola typu referencyjnego bezpośrednio
Kategoria Wydajność
Poprawka łamiąca lub nienaruszająca Niezgodność
Domyślnie włączone na platformie .NET 10 Nie.
Zastosowane języki C# i Visual Basic

Przyczyna

Typ odwołania deklaruje jawny konstruktor statyczny.

Opis reguły

Kiedy typ deklaruje jawny statyczny konstruktor, kompilator JIT dodaje sprawdzenie do każdej statycznej metody i konstruktora wystąpienia tego typu, 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, najczęściej pomijane są sprawdzanie konstruktorów statycznych. Inicjowanie statyczne jest gwarantowane, że nastąpi w jakimś momencie przed uzyskaniem dostępu do pól statycznych, jednak nie przed wywołaniem statycznej metody lub konstruktora instancji. 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 jedno z następujących stwierdzeń jest prawdziwe:

  • 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 w momencie ich zadeklarowania 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.
  • Konieczność wystąpienia globalnych zmian stanu spowodowanych przez inicjowanie statyczne jest kosztowna. Zmiany te muszą być zagwarantowane przed wywołaniem statycznej metody typu albo utworzeniem instancji tego 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 StaticConstructor, który narusza regułę, i typ NoStaticConstructor, który zastępuje konstruktor statyczny inicjalizacją inline, aby spełnić regułę.

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

Zwróć uwagę na dodanie flagi beforefieldinit w definicji CIL dla klasy 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