web-dev-qa-db-fra.com

Comment fonctionne un constructeur statique?

namespace MyNameSpace
{
    static class MyClass
    {
        static MyClass()
        {
            //Authentication process.. User needs to enter password
        }

        public static void MyMethod()
        {
            //Depends on successful completion of constructor
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyClass.MyMethod();
        }
    }
}

Voici la séquence que j'ai supposée

  1. Début du constructeur statique
  2. Fin du constructeur statique
  3. Début du principal
  4. Début de MyMethod
  5. Fin du principal

Maintenant, dans n'importe quel scénario, si 4 commencera avant 2, je suis foutu. C'est possible?

80
om471987

Vous n'avez posé qu'une seule question ici mais il y a une douzaine de questions que vous devriez avoir posées, donc je vais y répondre.

Voici la séquence que j'ai supposée

  1. Début du constructeur de classe (également appelé cctor)
  2. Fin du cctor
  3. début du Main
  4. début de MyMethod

Est-ce correct?

Non. La séquence correcte est:

  1. Démarrage de cctor pour Program, s'il y en a un. Il n'y a pas.
  2. Fin du cctor pour le programme, s'il y en a un. Il n'y a pas.
  3. Début du Main
  4. Démarrage de cctor pour MyClass
  5. Fin du cctor pour MyClass
  6. Début de MyClass.MyMethod

Et s'il y a un initialiseur de champ statique?

Le CLR est autorisé à modifier l'ordre dans lequel les initialiseurs de champ statiques s'exécutent dans certains cas. Voir la page de Jon sur le sujet pour plus de détails:

Les différences entre les constructeurs statiques et les initialiseurs de type

Est-il jamais possible d'appeler une méthode statique comme MyMethod avant la fin du cctor de cette classe?

Oui. Si le cctor lui-même appelle MyMethod, alors évidemment MyMethod sera appelé avant la fin du cctor.

Le cctor n'appelle pas MyMethod. Est-il possible qu'une méthode statique comme MyMethod soit appelée avant la fin du cctor de MyClass?

Oui. Si le cctor utilise un autre type dont le cctor appelle MyMethod, alors MyMethod sera appelé avant la fin du cctor MyClass.

Aucun processeur n'appelle MyMethod, directement ou indirectement! Est-il maintenant possible qu'une méthode statique comme MyMethod soit appelée avant la fin du cctor de MyClass?

Non.

Est-ce toujours vrai même si plusieurs threads sont impliqués?

Oui. Le cctor se terminera sur un thread avant que la méthode statique puisse être appelée sur n'importe quel thread.

Le cctor peut-il être appelé plus d'une fois? Supposons que deux threads provoquent l'exécution du cctor.

Le cctor est garanti d'être appelé au plus une fois, quel que soit le nombre de threads impliqués. Si deux threads appellent MyMethod "en même temps", ils courent. L'un d'eux perd la course et bloque jusqu'à ce que le cctor MyClass se termine sur le fil gagnant.

Le thread perdant blocs jusqu'à ce que le cctor soit terminé? Vraiment?

Vraiment.

Et si le cctor du thread gagnant appelle du code qui bloque un verrou précédemment pris par le thread perdant?

Vous avez alors une condition d'inversion d'ordre de verrouillage classique. Les blocages de votre programme. Pour toujours.

Cela semble dangereux. Comment puis-je éviter l'impasse?

Si ça fait mal quand vous faites ça, alors arrêtez de faire ça. Ne faites jamais quelque chose qui peut bloquer dans un cctor.

Est-ce une bonne idée de s'appuyer sur la sémantique d'initialisation de cctor pour appliquer des exigences de sécurité complexes? Et est-ce une bonne idée d'avoir un cctor qui fait les interactions avec les utilisateurs?

Les bonnes idées non plus. Mon conseil est que vous devez trouver un moyen différent de vous assurer que les conditions préalables à la sécurité de vos méthodes sont remplies.

217
Eric Lippert

Selon le MSDN , un constructeur statique:

Un constructeur statique est appelé automatiquement pour initialiser la classe avant la création de la première instance ou le référencement de tout membre statique.

Ainsi, le constructeur statique sera appelé avant que la méthode statique MyClass.MyMethod() soit invoquée (en supposant que ne soit pas également invoquée pendant la construction statique ou l'initialisation du champ statique) bien sûr).

Maintenant, si vous faites quelque chose d'asynchrone dans ce static constructor, alors c'est à vous de synchroniser ça.

23
James Michael Hare

Le n ° 3 est en fait n ° 1: l'initialisation statique ne démarre pas avant la première utilisation de la classe à laquelle il appartient.

Cela est possible si MyMethod est appelé à partir du constructeur statique ou d'un bloc d'initialisation statique. Si vous n'appelez pas MyMethod directement ou indirectement à partir de votre constructeur statique, ça devrait aller.

11
dasblinkenlight

De la documentation (accent sur le mien):

Un constructeur statique est appelé automatiquement pour initialiser la classe avant la création de la première instance ou tout membre statique est référencé .

9
ken

Vous pouvez garantir que 4 viendra toujours après 2 (si vous ne créez pas d'instance de votre classe à partir de votre méthode statique), mais il n'en va pas de même pour 1 et 3.

2
Scott Chamberlain

Le constructeur statique sera appelé avant l'exécution de mymethod. Cependant si vous êtes foutu si 4 est appelé avant 2 alors je vous suggère de repenser votre design. Ne devrait pas faire de toute façon des choses compliquées dans un constructeur statique.

2
Umair

Le CLR garantit que le constructeur statique s'exécute avant d'accéder à tous les membres statiques. Cependant, votre design est un peu malodorant. Il serait plus simple de faire quelque chose comme ça:

static void Main(string[] args) 
{ 
     bool userIsAuthenticated = MyClass.AuthenticateUser();
     if (userIsAuthenticated)
         MyClass.MyMethod(); 
 } 

Avec votre conception, si l'authentification échoue, la seule façon d'empêcher MyMethod de s'exécuter est de lever une exception.

2
phoog

Il est garanti que le constructeur d'une classe statique a été appelé avant l'exécution de l'une de ses méthodes. Exemple:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Press enter");
        Console.ReadLine();
        Boop.SayHi();
        Boop.SayHi();
        Console.ReadLine();
    }

}

static class Boop
{
    static Boop()
    {
        Console.WriteLine("Hi incoming ...");
    }

    public static void SayHi()
    {
        Console.WriteLine("Hi there!");
    }
}

Production:

Appuyez sur Entrée

// après avoir appuyé sur enter

Salut entrant ...

Salut!

Salut!

2
haiyyu

Voici l'ordre réel dans lequel les choses se déroulent:

  1. Début de Main
  2. Début du constructeur statique MyClass
  3. Fin du constructeur statique MyClass
  4. Début de MyMethod
  5. Fin de Main
1
user370770

Ou vous pouvez entrer dans le débogueur.

0
saille