2009-12-30 3 views
2

Comme j'ai appris que les objets statiques dans les classes sont construits lorsque la classe est référencée pour la première fois. Cependant, je trouverais parfois utile d'initialiser la statique lorsque le programme est démarré. Existe-t-il une méthode (en utilisant des annotations) pour l'appliquer?Forcer la construction d'objets statiques

Répondre

7

Vous ne pouvez pas le faire avec des attributs (sans code supplémentaire), mais pouvez initialiser le type de force avec la réflexion.

Par exemple:

foreach (Type type in assembly.GetTypes()) 
{ 
    ConstructorInfo ci = type.TypeInitializer; 
    if (ci != null) 
    { 
     ci.Invoke(null); 
    } 
} 

Notez que ce ne sera pas initializers de type Invoke pour les types génériques, parce que vous auriez besoin de préciser les arguments de type. Vous devriez également noter qu'il va forcer l'initialiseur de type à être exécuté même s'il a déjà été exécuté, ce qui va à l'encontre de l'expérience normale. Je suggère que si vous vraiment besoin de faire cela (et je voudrais essayer de changer votre conception si vous n'avez pas besoin si possible), vous devez créer votre propre attribut, et changer le code à quelque chose comme:

foreach (Type type in assembly.GetTypes()) 
{ 
    if (type.GetCustomAttributes(typeof(..., false)).Length == 0) 
    { 
     continue; 
    } 
    ConstructorInfo ci = type.TypeInitializer; 
    if (ci != null) 
    { 
     ci.Invoke(null, null); 
    } 
} 

vous pouvez le faire avec LINQ, il est vrai:

var initializers = from type in assembly.GetTypes() 
        let initializer = type.TypeInitializer 
        where initializer != null && 
         type.GetCustomAttributes(typeof(..., false).Length > 0 
        select initializer; 
foreach (ConstructorInfo initializer in initializers) 
{ 
    initializer.Invoke(null, null); 
} 
+1

Mon intention est que déclarer simplement une classe avec une instance statique pourrait déclencher un comportement. Comment cela peut-il être réalisé en .net? – kyku

+1

Ou RuntimeHelpers.RunClassConstructor peut être utilisé. –

+2

@kyku: Non, pas sans quelque chose comme le code ci-dessus. –

5

Faites simplement référence à un champ statique de ce type au début de votre application. Il n'y a aucun moyen de le faire uniquement en modifiant le code de la classe site de définition.

+0

+1 pour une meilleure réponse que celle de Jon Skeet! Vous devez faire quelque chose d'explicite, alors pourquoi ne pas le rendre simple et explicite plutôt que d'utiliser des attributs de réflexion ou personnalisés. – Joe

+0

Il n'y a donc aucun moyen que mes cours s'auto-enregistrent? – kyku

+0

Non, il n'y en a pas. –

1

Le CLR prend en charge module initializers, qui est probablement ce que vous êtes l en train de chercher. Plutôt académique étant donné vos tags, cette fonctionnalité n'est pas disponible dans le langage C#, seulement le langage C++/CLI.

La solution de contournement est entièrement indolore, appelez explicitement une méthode statique (Initialize?).

0

Ok, j'ai découvert que cela peut être fait de la façon suivante. Un appel unique à InvokeImplicitInitializers() dans Main() sera appelez Initialize() dans chaque classe qui a défini cette méthode.

using System; 
using System.Reflection; 

namespace Test 
{ 
    public class Class1 
    { 
     static Class1() 
     { 
      Console.WriteLine("Class1: static constructor"); 
     } 

     public static void Initialize() 
     { 
      Console.WriteLine("Class1: initialize method"); 
     } 
    } 

    public static class Class2 
    { 
     public static void Initialize() 
     { 
      Console.WriteLine("Class2: initialize method"); 
     } 
    } 


    class MainClass 
    { 
     public static void InvokeImplicitInitializers(Assembly assembly) 
     { 
      foreach (Type type in assembly.GetTypes()) 
      { 
       MethodInfo mi = type.GetMethod("Initialize"); 
       if (mi != null) 
       { 
        mi.Invoke(null, null); 
       } 
      } 
     } 

     public static void Main (string[] args) 
     { 
      InvokeImplicitInitializers(Assembly.GetCallingAssembly()); 
     } 
    } 
} 

Qu'en pensez-vous? Est-ce un motif ou un motif anit?

+0

C'est un anti-pattern en ce qui me concerne. Il y a peut-être une bonne raison de le faire dans des circonstances très précises, mais j'ai ... encore à voir une bonne raison pour cela. La raison pour laquelle je suis si contre, c'est que nous avons eu beaucoup de problèmes avec une initialisation statique et implicite au travail et c'était extrêmement frustrant de travailler avec, surtout lorsque la commande est requise. Il finit par être un gâchis spaghetti vaudou qui est difficile à comprendre et à maintenir. Il tue également la testabilité. Je chercherais sérieusement une alternative! –

Questions connexes