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