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
Maintenant, dans n'importe quel scénario, si 4 commencera avant 2, je suis foutu. C'est possible?
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
cctor
)Est-ce correct?
Non. La séquence correcte est:
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.
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.
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.
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é .
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.
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.
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.
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!
Voici l'ordre réel dans lequel les choses se déroulent:
Main
MyClass
MyClass
MyMethod
Main
Ou vous pouvez entrer dans le débogueur.