Constructeurs statiques (Guide de programmation C#)

Un constructeur statique est utilisé pour initialiser toutes les données statiques ou pour exécuter une action particulière qui ne doit être exécutée qu’une seule fois. Il est automatiquement appelé avant la création de la première instance ou le référencement d’un membre statique.

class SimpleClass
{
    // Static variable that must be initialized at run time.
    static readonly long baseline;

    // Static constructor is called at most one time, before any
    // instance constructor is invoked or member is accessed.
    static SimpleClass()
    {
        baseline = DateTime.Now.Ticks;
    }
}

Remarques

Les constructeurs statiques ont les propriétés suivantes :

  • Un constructeur statique ne prend pas de modificateur d’accès ou a des paramètres.

  • Une classe ou struct ne peut pas avoir de constructeur statique.

  • Les constructeurs statiques ne peuvent pas être hérités ou surchargés.

  • Un constructeur statique ne peut pas être appelé directement et est uniquement destiné à être appelé par le Common Language Runtime (CLR). Il est appelé automatiquement.

  • L’utilisateur n’a aucun contrôle sur le moment d’exécution du constructeur statique dans le programme.

  • Un constructeur statique est appelé automatiquement. Elle initialise la classe avant la création de la première instance ou la référence à tous les membres statiques. Un constructeur statique s’exécute avant un constructeur d’instance. Le constructeur statique d’un type est appelé lorsqu’une méthode statique assignée à un événement ou à un délégué est appelée, et non quand elle est assignée. Si des initialiseurs de variable de champ statique sont présents dans la classe du constructeur statique, ils sont exécutés dans l’ordre textuel dans lequel ils apparaissent dans la déclaration de classe. Les initialiseurs s’exécutent immédiatement avant l’exécution du constructeur statique.

  • Si vous ne fournissez pas de constructeur statique pour initialiser les champs statiques, tous les champs statiques sont initialisés à leur valeur par défaut, comme indiqué dans les valeurs par défaut des types C#.

  • Si un constructeur statique lève une exception, le runtime ne l’appelle pas une deuxième fois, et le type reste non initialisé pendant toute la durée de vie du domaine d’application. En règle générale, une exception TypeInitializationException est levée lorsqu’un constructeur statique ne parvient pas à instancier un type ou quand une exception non gérée se produit dans un constructeur statique. Pour les constructeurs statiques qui ne sont pas explicitement définis dans le code source, la résolution des problèmes peut nécessiter l’inspection du code IL (Intermediate Language).

  • La présence d’un constructeur statique empêche l’ajout de l’attribut de type BeforeFieldInit. Cela limite l’optimisation du runtime.

  • Un champ déclaré en tant que static readonly ne peut être attribué que dans le cadre de sa déclaration ou dans un constructeur statique. Lorsqu’un constructeur statique explicite n’est pas requis, initialisez les champs statiques au niveau de la déclaration plutôt qu’à l’aide d’un constructeur statique pour une meilleure optimisation du Runtime.

  • Le runtime appelle un constructeur statique au moins une fois dans un même domaine d’application. Cet appel est effectué dans une région verrouillée en fonction du type spécifique de la classe. Aucun mécanisme de verrouillage supplémentaire n’est nécessaire dans le corps d’un constructeur statique. Pour éviter le risque d’interblocages, ne bloquez pas le thread actuel dans les constructeurs et les initialiseurs statiques. Par exemple, n’attendez pas les tâches, les threads, les handles d’attente ou les événements, n’acquérez pas de verrous et n’exécutez pas d’opérations parallèles de blocage telles que les boucles parallèles Parallel.Invoke et les requêtes LINQ parallèles.

Notes

S’il n’est pas directement accessible, la présence d’un constructeur statique explicite doit être documentée pour faciliter la résolution des exceptions de l’initialisation.

Usage

  • Généralement, on utilise des constructeurs statiques quand la classe utilise un fichier journal et que le constructeur sert à écrire des entrées dans ce fichier.

  • Les constructeurs statiques sont également utiles pour la création de classes wrapper pour du code non managé, quand le constructeur peut appeler la méthode LoadLibrary.

  • Les constructeurs statiques sont également un emplacement pratique pour appliquer des contrôles au moment de l’exécution sur le paramètre de type qui ne peuvent pas être vérifiés au moment de la compilation via des contraintes de paramètre de type.

Exemple

Dans cet exemple, la classe Bus possède un constructeur statique. Quand la première instance de Bus est créée (bus1), le constructeur statique est appelé pour initialiser la classe. L’exemple de sortie vérifie que le constructeur statique s’exécute une seule fois, même si deux instances de Bus sont créées, et qu’il s’exécute avant le constructeur d’instance.

public class Bus
{
    // Static variable used by all Bus instances.
    // Represents the time the first bus of the day starts its route.
    protected static readonly DateTime globalStartTime;

    // Property for the number of each bus.
    protected int RouteNumber { get; set; }

    // Static constructor to initialize the static variable.
    // It is invoked before the first instance constructor is run.
    static Bus()
    {
        globalStartTime = DateTime.Now;

        // The following statement produces the first line of output,
        // and the line occurs only once.
        Console.WriteLine("Static constructor sets global start time to {0}",
            globalStartTime.ToLongTimeString());
    }

    // Instance constructor.
    public Bus(int routeNum)
    {
        RouteNumber = routeNum;
        Console.WriteLine("Bus #{0} is created.", RouteNumber);
    }

    // Instance method.
    public void Drive()
    {
        TimeSpan elapsedTime = DateTime.Now - globalStartTime;

        // For demonstration purposes we treat milliseconds as minutes to simulate
        // actual bus times. Do not do this in your actual bus schedule program!
        Console.WriteLine("{0} is starting its route {1:N2} minutes after global start time {2}.",
                                this.RouteNumber,
                                elapsedTime.Milliseconds,
                                globalStartTime.ToShortTimeString());
    }
}

class TestBus
{
    static void Main()
    {
        // The creation of this instance activates the static constructor.
        Bus bus1 = new Bus(71);

        // Create a second bus.
        Bus bus2 = new Bus(72);

        // Send bus1 on its way.
        bus1.Drive();

        // Wait for bus2 to warm up.
        System.Threading.Thread.Sleep(25);

        // Send bus2 on its way.
        bus2.Drive();

        // Keep the console window open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Sample output:
    Static constructor sets global start time to 3:57:08 PM.
    Bus #71 is created.
    Bus #72 is created.
    71 is starting its route 6.00 minutes after global start time 3:57 PM.
    72 is starting its route 31.00 minutes after global start time 3:57 PM.
*/

spécification du langage C#

Pour plus d’informations, voir la section Constructeurs statiques de la spécification du langage C#.

Voir aussi