CA1810: Inizializzare i campi statici del tipo di riferimento inline

Proprietà valore
ID regola CA1810
Title Inizializzare i campi statici del tipo di riferimento inline
Categoria Prestazioni
La correzione causa un'interruzione o meno Non causa un'interruzione
Abilitato per impostazione predefinita in .NET 9 No

Causa

Un tipo riferimento dichiara un costruttore statico esplicito.

Descrizione regola

Quando un tipo dichiara un costruttore statico esplicito, tramite il compilatore JIT (Just-In-Time) viene aggiunto un controllo a ogni metodo statico del tipo e a ogni costruttore di istanza del tipo per assicurare che il costruttore statico sia stato precedentemente chiamato. L'inizializzazione statica viene attivata quando si accede a un membro statico o quando viene creata un'istanza del tipo. Tuttavia, l'inizializzazione statica non viene attivata se si dichiara una variabile del tipo ma non la si usa, che può essere importante se l'inizializzazione cambia lo stato globale.

Quando tutti i dati statici vengono inizializzati inline e non viene dichiarato un costruttore statico esplicito, i compilatori CIL (Common Intermediate Language) aggiungono il beforefieldinit flag e un costruttore statico implicito, che inizializza i dati statici, alla definizione del tipo CIL. Quando il compilatore JIT rileva il beforefieldinit flag, nella maggior parte dei casi i controlli del costruttore statico non vengono aggiunti. L'inizializzazione statica viene garantita in un determinato momento prima dell'accesso a qualsiasi campo statico, ma non prima che venga richiamato un metodo statico o un costruttore di istanza. Si noti che l'inizializzazione statica può verificarsi in qualsiasi momento dopo la dichiarazione di una variabile del tipo.

I controlli dei costruttori statici possono ridurre le prestazioni. Spesso un costruttore statico viene usato solo per inizializzare i campi statici, nel qual caso è necessario assicurarsi che l'inizializzazione statica venga eseguita solo prima del primo accesso di un campo statico. Il beforefieldinit comportamento è appropriato per questi e la maggior parte degli altri tipi. È inappropriato solo quando l'inizializzazione statica influisce sullo stato globale e una delle condizioni seguenti è vera:

  • L'effetto sullo stato globale è costoso e non è necessario se il tipo non viene usato.

  • È possibile accedere agli effetti dello stato globale senza accedere ad alcun campo statico del tipo.

Come correggere le violazioni

Per correggere una violazione di questa regola, inizializzare tutti i dati statici quando vengono dichiarati e rimuovere il costruttore statico.

Quando eliminare gli avvisi

È possibile eliminare un avviso da questa regola se si applica uno dei seguenti elementi:

  • Le prestazioni non sono un problema.
  • Le modifiche di stato globali causate dall'inizializzazione statica sono costose o devono essere garantite prima che venga chiamato un metodo statico del tipo o venga creata un'istanza del tipo.

Eliminare un avviso

Se si vuole eliminare una singola violazione, aggiungere direttive del preprocessore al file di origine per disabilitare e quindi riabilitare la regola.

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

Per disabilitare la regola per un file, una cartella o un progetto, impostarne la gravità none su nel file di configurazione.

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

Per altre informazioni, vedere Come eliminare gli avvisi di analisi del codice.

Esempio

Nell'esempio seguente viene illustrato un tipo, StaticConstructor, che viola la regola e un tipo , NoStaticConstructor, che sostituisce il costruttore statico con l'inizializzazione inline per soddisfare la regola.

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

Si noti l'aggiunta beforefieldinit del flag nella definizione CIL per la NoStaticConstructor classe .

.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