CA1810 : Initialisez les champs statiques de type référence en ligne

Propriété Value
Identificateur de la règle CA1810
Titre Initialisez les champs statiques de type référence en ligne
Catégorie Performances
Le correctif est cassant ou non cassant Sans rupture
Activé par défaut dans .NET 8 Non

Cause

Un type référence déclare un constructeur statique explicite.

Description de la règle

Lorsqu'un type déclare un constructeur statique explicite, le compilateur juste-à-temps (JIT, Just-In-Time) ajoute une vérification à chacun des méthodes statiques et constructeurs d'instances du type afin de garantir que le constructeur statique a été appelé précédemment. L’initialisation statique est déclenchée lorsqu’un membre statique est accessible ou lorsqu’une instance du type est créée. Toutefois, l’initialisation statique n’est pas déclenchée si vous déclarez une variable du type mais que vous ne l’utilisez pas, ce qui peut être important si l’initialisation change d’état global.

Lorsque toutes les données statiques sont initialisées inline et qu’un constructeur statique explicite n’est pas déclaré, les compilateurs CIL (Common Intermediate Language) ajoutent l’indicateur beforefieldinit et un constructeur statique implicite, qui initialise les données statiques, à la définition de type CIL. Lorsque le compilateur JIT rencontre l’indicateur beforefieldinit, la plupart du temps, les vérifications de constructeur statique ne sont pas ajoutées. L’initialisation statique est garantie à un moment donné avant l’accès aux champs statiques, mais pas avant l’appel d’une méthode statique ou d’un constructeur d’instance. Notez que l’initialisation statique peut se produire à tout moment après la déclaration d’une variable du type.

Les vérifications des constructeurs statiques peuvent diminuer les performances. Souvent, un constructeur statique est utilisé uniquement pour initialiser des champs statiques. Dans ce cas, vous devez uniquement vous assurer que l’initialisation statique se produit avant le premier accès d’un champ statique. Le comportement beforefieldinit est approprié pour ces types et la plupart des autres. Il n’est inapproprié que lorsque l’initialisation statique affecte l’état global et que l’une des conditions suivantes est vraie :

  • L’effet sur l’état global est coûteux et n’est pas obligatoire si le type n’est pas utilisé.

  • Les effets d’état global sont accessibles sans accéder aux champs statiques du type.

Comment corriger les violations

Pour corriger une violation de cette règle, initialisez toutes les données statiques lorsqu’elles sont déclarées et supprimez le constructeur statique.

Quand supprimer les avertissements

Il est sûr de supprimer un avertissement de cette règle si l’un des éléments suivants s’applique :

  • Les performances ne sont pas un problème.
  • Les modifications d’état globales provoquées par l’initialisation statique sont coûteuses ou doivent être garanties de se produire avant qu’une méthode statique du type soit appelée ou qu’une instance du type soit créée.

Supprimer un avertissement

Si vous voulez supprimer une seule violation, ajoutez des directives de préprocesseur à votre fichier source pour désactiver et réactiver la règle.

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

Pour désactiver la règle sur un fichier, un dossier ou un projet, définissez sa gravité sur none dans le fichier de configuration.

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

Pour plus d’informations, consultez Comment supprimer les avertissements de l’analyse de code.

Exemple

L’exemple suivant montre un type, StaticConstructor, qui enfreint la règle, et un type, NoStaticConstructor, qui remplace le constructeur statique par une initialisation inline pour satisfaire la règle.

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

Notez l’ajout de l’indicateur beforefieldinit sur la définition CIL de 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