2010-06-02 5 views
4

Oui exactement ce que je veux faire :) Au moins pour une classe particulière. Le problème est que je crée une instance statique d'un objet mais je ne l'utilise pas directement. Comme je fais certaines opérations dans le constructeur, comme ajouter l'objet à une liste, le constructeur doit être invoqué au moins une fois avant d'avoir la liste.Force C# Compiler pour créer une instance d'objet inutilisée

Je suppose que le compilateur optimise simplement l'objet inutilisé.

Il doit y avoir une solution simple: -/

EDIT

Ok peut être me manque quelque chose. Laisse moi poster mon code. J'ai écrit une classe pour un but personnalisé enum.

 public class TypeSafeEnum<TNameType, TValueType> 
     { 
     protected readonly TNameType name; 
     protected readonly TValueType value; 

     private static List<TypeSafeEnum<TNameType, TValueType>> listEnums = new List<TypeSafeEnum<TNameType, TValueType>>(); 

     protected TypeSafeEnum(TNameType name, TValueType value) 
     { 
      this.name = name; 
      this.value = value; 

      listEnums.Add(this); 
     } 

     public TNameType Name 
     { 
      get { return name; } 
     } 

     public TValueType Value 
     { 
      get { return value; } 
     } 

     public static TypeSafeEnum<TNameType, TValueType> GetName(TNameType name) 
     { 
      TypeSafeEnum<TNameType, TValueType> tse = null; 
      for (int i = 0; i < listEnums.Count; i++) 
      { 
      TypeSafeEnum<TNameType, TValueType> typeSafeEnum = listEnums[i]; 
      if (EqualityComparer<TNameType>.Default.Equals(typeSafeEnum.name, name)) 
      { 
       tse = typeSafeEnum;    
      } 
      } 
      return tse; 
     } 

     public static TypeSafeEnum<TNameType, TValueType> GetValue(TValueType value) 
     { 
      TypeSafeEnum<TNameType, TValueType> tse = null; 
      for (int i = 0; i < listEnums.Count; i++) 
      { 
      TypeSafeEnum<TNameType, TValueType> typeSafeEnum = listEnums[i]; 
      if (EqualityComparer<TValueType>.Default.Equals(typeSafeEnum.value, value)) 
      { 
       tse = typeSafeEnum; 
      } 
      } 
      return tse; 
     } 

     public static TNameType[] GetNames() 
     { 
      TNameType[] names = new TNameType[listEnums.Count]; 
      for (int i = 0; i < listEnums.Count; i++) 
      { 
      TypeSafeEnum<TNameType, TValueType> typeSafeEnum = listEnums[i]; 
      names[i] = typeSafeEnum.name; 
      } 
      return names; 
     } 

     public static TValueType[] GetValues() 
     { 
      TValueType[] values = new TValueType[listEnums.Count]; 
      for (int i = 0; i < listEnums.Count; i++) 
      { 
      TypeSafeEnum<TNameType, TValueType> typeSafeEnum = listEnums[i]; 
      values[i] = typeSafeEnum.value; 
      } 
      return values; 
     } 
     } 


     public abstract class StringEnum : TypeSafeEnum<string, int> 
     { 
      protected StringEnum(string name, int value) : base(name, value) 
      { 
      } 
     } 


     public sealed class FileOptionEnum : StringEnum 
     { 
      public static readonly FileOptionEnum Name = new FileOptionEnum("Name", 0); 
      public static readonly FileOptionEnum Extension = new FileOptionEnum("Extension", 1); 
      public static readonly FileOptionEnum Size = new FileOptionEnum("Size", 2); 
      public static readonly FileOptionEnum LastModified = new FileOptionEnum("Last Modified", 3); 
      public static readonly FileOptionEnum LastOpened = new FileOptionEnum("Last Opened", 4); 
      public static readonly FileOptionEnum Created = new FileOptionEnum("Created", 5); 

      public FileOptionEnum(string name, int value) : base(name, value) 
      { 
      } 
     } 

Voici comment je l'utilise:

 // if I omit this line it returns me empty array 
     FileOptionEnum @enum = FileOptionEnum.Name; 
     string[] names = FileOptionEnum.GetNames(); 
     cbFileOptions.Items.AddRange(names); 
+3

Peut-être que vous pourriez discuter de ce que vous essayez d'accomplir; il pourrait y avoir une solution de rechange? –

+1

Une "instance statique" n'existe pas. Je suppose que vous voulez dire que vous avez une variable statique que vous initialisez en créant une instance de la classe? – Guffa

+0

Cette création ne fonctionnera pas. – SLaks

Répondre

2

Vous pouvez simplement écrire

new YourObject(); 

Ce ne sera pas optimisé loin.
Cependant, à moins que le constructeur de la classe ne s'enregistre quelque part (par exemple, ajouter l'objet à la liste ou au champ statique, ou ajouter un gestionnaire d'événements à autre chose), l'objet sera probablement immédiatement récupéré.

2

Tout d'abord, vérifiez que le compilateur optimise réellement le code. Les chances sont, ce n'est pas le cas: si votre appel constructeur a des effets secondaires, le compilateur n'a pas vraiment le droit de s'en débarrasser.

Et si elle ne fait pas optimisés, vous pouvez utiliser la méthode GC.KeepAlive pour garantir que l'objet reste:

GC.KeepAlive(new MyObj()); 

Cette méthode ne fait pas vraiment quoi que ce soit - il a un corps vide. Mais c'est spécial d'une manière qui ne peut pas être optimisée. Donc, vous l'appelez avec un argument, alors cet argument ne peut pas non plus être optimisé.

+2

Cela entraînera une fuite de mémoire. – SLaks

+0

@SLaks: Pourquoi est-ce qu'il y a une fuite de mémoire? L'utilisation de la déclaration keep-alive semble stupide. Pourquoi essayer de conserver un nouvel objet en vie lorsque l'appel signale au GC que l'objet nouvellement créé peut être récupéré. Est-ce la raison pour laquelle cela "fuira la mémoire"? – AMissico

+0

Parce que l'objet ne sera jamais collecté. Selon ce que l'objet est et ce qu'il fait, cela peut ou peut ne pas être un problème. – SLaks

0

Si vous utilisez simplement une fonctionnalité statique, pourquoi utiliser une instance? Créez une classe statique et disposez d'une méthode statique 'Initialize()' que vous pouvez appeler pour configurer votre objet.

1

Votre idée ne fonctionnera pas.

Le champ List<TypeSafeEnum<TNameType, TValueType>> listEnums statique sera partagé par toutes les classes TypeSafeEnum qui ont le même nom et les mêmes types de valeurs.

Pour résoudre ce problème, ajoutez un paramètre pour la classe ENUM réelle, comme ceci:

public class TypeSafeEnum<TEnum, TName, TValue> where TEnum : TypeSafeEnum<TEnum, TName, TValue> 

(Vous pouvez remplacer tous vos TypeSafeEnum<...> champs et paramètres avec TEnum)

Je suis assez sûr que cela va également résoudre votre question réelle.
Étant donné que la classe de base TypeSafeEnum fait maintenant référence à la classe enum héritée, le constructeur statique de la classe héritée sera exécuté, initialisant les valeurs.

+0

Je vois. merci. Alors qu'est-ce que vous suggérez? – Heka

+0

La liste OK fonctionne maintenant correctement, mais le problème persiste. :( FileOptionEnum.GetNames() donne toujours une liste vide si FileOptionEnum.Name n'est pas appelé manuellement – Heka

+0

Vous pouvez utiliser la réflexion dans un constructeur statique de la classe de base. – SLaks

0

Les membres statiques ne sont pas garantis d'être initialisés jusqu'à ce que vous essayiez d'y accéder explicitement. Vous pouvez contourner cela en créant un constructeur statique explicite (pour éviter le comportement de beforeFieldInit) et accéder explicitement à une méthode statique (comme une méthode Init fictive) pour forcer l'initialisation statique.

Questions connexes