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(ssortingng[] args) { MyClass.MyMethod(); } } } 

Voici la séquence que j’ai prise

  1. Début du constructeur statique
  2. Fin du constructeur statique
  3. Début de la principale
  4. Début de MyMethod
  5. Fin de main

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

Vous avez seulement posé une question ici mais il y a une douzaine de questions que vous auriez dû poser, alors je vais répondre à toutes les questions.

Voici la séquence que j’ai prise

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

Est-ce correct?

La séquence correcte est:

  1. Début du cctor pour le programme, 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 de Main
  4. Début du 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 d’exécution des initialiseurs de champs statiques 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 types

Est-il possible qu’une méthode statique comme MyMethod soit appelée avant la fin du cctor de cette classe?

Oui. Si le cctor lui-même appelle MyMethod, alors évidemment MyMethod sera appelée avant que le cctor ne se termine.

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 cctor n’appelle MyMethod, directement ou indirectement! Maintenant, est-il 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 tous deux 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” alors ils courent. L’un d’eux perd la course et se bloque jusqu’à ce que le cctor MyClass se termine sur le fil gagnant.

Le fil de perte se bloque jusqu’à ce que le cctor soit terminé? Vraiment ?

Vraiment.

Alors, que se passe-t-il si le cctor sur le thread gagnant appelle un code qui bloque sur un verrou précédemment pris par le thread perdant ?

Ensuite, vous avez une condition d’inversion d’ordre de locking classique. Vos impasses de programme. Pour toujours.

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

Si cela vous fait mal, arrêtez de le faire . Ne faites jamais quelque chose qui puisse bloquer dans un cctor.

Est-ce une bonne idée de compter 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 interagit avec l’utilisateur?

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

Selon le MSDN , un constructeur statique:

Un constructeur statique est appelé automatiquement pour initialiser la classe avant que la première instance soit créée ou que des membres statiques soient référencés.

Ainsi, le constructeur statique sera appelé avant que la méthode statique MyClass.MyMethod() soit invoquée (en supposant que cela ne soit pas non plus invoqué lors de la construction statique ou de l’initialisation des champs statiques).

Maintenant, si vous faites quelque chose d’asynchrone dans ce static constructor , alors vous devez le synchroniser.

Le # 3 est en fait # 1: l’initialisation statique ne démarre pas avant la première utilisation de la classe à laquelle elle appartient.

Il est possible que MyMethod soit appelée depuis le constructeur statique ou un bloc d’initialisation statique. Si vous n’invoquez pas MyMethod directement ou indirectement à partir de votre constructeur statique, cela devrait aller.

De la documentation (emphase la mienne):

Un constructeur statique est appelé automatiquement pour initialiser la classe avant que la première instance soit créée ou que des membres statiques soient référencés .

Vous pouvez garantir que 4 viendra toujours après 2 (si vous ne créez pas une instance de votre classe à partir de votre méthode statique), cependant, ce n’est pas le cas pour 1 et 3.

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

Le CLR garantit que le constructeur statique s’exécute avant d’accéder aux membres statiques. Cependant, votre design est un peu puant. Il serait plus simple de faire quelque chose comme ceci:

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

Avec votre conception, si l’authentification échoue, le seul moyen d’empêcher l’exécution de MyMethod est de lancer une exception.

Il est garanti que le constructeur d’une classe statique a été appelé avant que ses méthodes ne soient exécutées. Exemple:

 class Program { static void Main(ssortingng[] 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!"); } } 

Sortie:

Appuyez sur Entrée

// après avoir appuyé sur enter

Salut entrant …

Salut!

Salut!

Voici l’ordre dans lequel les choses se passent:

  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

Ou vous pouvez passer à travers le débogueur.