Comment déclencher un constructeur statique

code:

class Base where T:Base,new() where U :class { protected static U _val = null; internal static void ShowValue() { if(_val == null)new T(); //Without this line, it won't work as expected Console.WriteLine (_val); } internal static void Virtual() { Console.WriteLine ("Base"); } } class Deriv :Base { static Deriv() { _val = "some ssortingng value"; } internal static new void Virtual () { Console.WriteLine ("Deriv"); } } public static void Main (ssortingng[] args) { Deriv.ShowValue(); Deriv.Virtual(); } 

Grâce aux génériques de .NET, je peux créer un groupe de classes spécifiques en réutilisant des méthodes statiques génériques définies dans la classe de base générique. Il peut imiter le polymorphism d’inheritance dans une certaine mesure. Mais pour initialiser différentes versions de champs statiques, je dois utiliser des constructeurs statiques. Malheureusement, nous ne pouvons pas les appeler directement. Par conséquent, nous devons trouver un moyen de déclencher son invocation. L’exemple donné ci-dessus montre un chemin. Mais je n’aime ni l’approche d’instanciation ni l’approche de reflection. Nous ne pouvons pas non plus imposer de contrainte sur une méthode statique d’un paramètre générique. Alors, j’aimerais demander s’il y a une autre façon de faire ce genre de travail!

Merci d’avance!

~~~~~~~~~~~~~~~~~

Quelques conclusions (peut-être un peu tôt):

Il semble qu’il n’y ait pas de solution de rechange pour faire face à ce genre de situation. Je dois instancier une sous-classe ou utiliser la reflection. Etant donné que les .cctors doivent simplement être appelés une fois, je suis favorable à l’approche de reflection, car dans certains cas, une contrainte new () n’est tout simplement pas un choix – comme si vous n’étiez pas censé exposer le ctor sans paramètre à l’utilisateur.

Après avoir mené d’autres expériences, je découvre que les .cctors peuvent être appelés plusieurs fois mais seule la première invocation affectera la définition des champs statiques. C’est bizarre, mais une bonne bizarrerie!

  class MyClass { static int _val = 0; static MyClass() { _val++; Console.WriteLine (_val); } } public static void Main (ssortingng[] args) { ConstructorInfo ci = typeof(MyClass).TypeInitializer; ci.Invoke(new object[0]); ci.Invoke(new object[0]); ci.Invoke(new object[0]); } //result: //1 //1 //1 //1 

Je vous conseillerais fortement de repenser votre conception. Tenter d’utiliser ce type de solution de contournement pour «inheritance statique» se bat contre certaines des conceptions fondamentales de .NET.

Vous ne savez pas quel problème plus important vous essayez de résoudre, mais essayer un code “intelligent” comme celui-ci pour simuler l’inheritance mènera à un code très difficile à maintenir et à diagnostiquer à long terme.

Sans réellement utiliser un membre de Deriv (ou en créer une instance), vous ne déclencherez pas le constructeur statique. Il est important de comprendre que Deriv.ShowValue() est essentiellement converti en un appel à

 Base.ShowValue(); 

… donc vous Deriv rien sur Deriv . Votre code d’appel serait en fait plus clair s’il était écrit de cette façon.

EDIT: Une autre raison (clairement regrettable) d’éviter d’utiliser explicitement les initialiseurs de types est qu’il existe un bogue dans .NET 4.5 qui provoque la levée incorrecte d’une exception dans certains cas. Voir ma question sur le sujet pour plus d’informations.

Vous n’avez aucun contrôle sur le moment où le constuctor statique s’exécutera, mais il est garanti qu’il s’exécutera avant d’accéder à une propriété ou à une méthode statique et avant l’instanciation.

Il n’ya vraiment aucune raison de vouloir que le constructeur statique s’exécute plus tôt. Si vous n’utilisez rien de la classe mais que vous voulez que le code du constructeur statique soit exécuté, alors quelque chose ne va pas dans votre conception.

La solution correcte consiste à appeler le type initializer (= constructeur statique) comme suit:

 typeof(T).TypeInitializer.Invoke(null, null); 

Il faut les deux null s. La spécification d’une seule MemberAccessException donne une MemberAccessException .

Ainsi, votre code peut vouloir ressembler à ceci:

 internal static void ShowValue() { if (_val == null) { if (typeof(T).TypeInitializer != null) typeof(T).TypeInitializer.Invoke(null, null); if (_val == null) throw new InvalidOperationException(ssortingng.Format("The type initializer of {0} did not initialize the _val field.", typeof(T))); } Console.WriteLine(_val); } 

Et avec cela, vous pouvez supprimer la contrainte new() .

Les constructeurs statiques sont automatiquement, une seule fois. Vous ne pouvez pas les appeler vous-même.

Un exemple d’ici:

 public class Bus { // Static constructor: static Bus() { System.Console.WriteLine("The static constructor invoked."); } public static void Drive() { System.Console.WriteLine("The Drive method invoked."); } } class TestBus { static void Main() { Bus.Drive(); } } 

sortie:

 The static constructor invoked. The Drive method invoked. 

Je vous renvoie à l’article de MSDN sur les constructeurs statiques et à environ 10% sur la page:

Un constructeur statique est appelé automatiquement pour initialiser la classe avant la création de la première instance ou la référence de tous les membres statiques.