2010-12-08 28 views
2

J'essaie de faire fonctionner une classe enum personnalisée qui devrait me permettre de créer des énumérations avec des identifiants conviviaux et une valeur arbitraire associée. jusqu'à présent si bien:Comportement étrange avec des champs statiques

public class EnumBase<T, E> 
    where E : class 
{ 
    private static readonly List<E> list = new List<E>(); 

    private string text; 
    private T value; 

    public string Text { get { return text; } } 
    public T Value { get { return value; } } 

    public EnumBase(string text, T value) 
    { 
     this.text = text; 
     this.value = value; 
     list.Add(this as E); 
    } 

    protected static IEnumerable<E> ItemList 
    { 
     get { return list; } 
    } 
} 

public class Zahlungsart : EnumBase<int, Zahlungsart> 
{ 
    public static readonly Zahlungsart Erlagsschein = new Zahlungsart("Erlagsschein", 0); 
    public static readonly Zahlungsart Lastschrift = new Zahlungsart("Lastschrift", 1); 

    private Zahlungsart(string text, int value) : base(text, value) { } 
    public static new IEnumerable<Zahlungsart> ItemList { get { return EnumBase<int, Zahlungsart>.ItemList; } } 
} 

Et maintenant mon problème:

Console.WriteLine(Zahlungsart.ItemList.Count()); 

La déclaration suivante me donne 0, au lieu de 2. Le problème est dû à beforefieldinit, je pense. Je pourrais contourner cela en appelant directement une méthode de l'enum spécifique qui forcerait les champs statiques à charger, mais ce n'est pas la meilleure solution, je pense.

Indice: ne proposez pas une sorte d'attribut [UserfriendlyName()] pour enum ici, je les connais déjà.

EDIT Merci, hans. J'avais en effet une faute de frappe dans mon propre code, appelant la mauvaise spécialisation générique. Maintenant, ma question est, puis-je me débarrasser de la redéfinition de ItemList dans chaque sous-classe, mais il semble que ce soit nécessaire pour obtenir les champs statiques initialisés.

+0

Lorsque je cours exactement le même code, j'obtiens "2" comme sortie. – cdhowie

Répondre

1

Votre code ne résout pas le problème. Mais vous obtiendrez un repro si vous modifiez la propriété comme ceci:

public new static IEnumerable<Zahlungsart> ItemList { 
     get { return EnumBase<uint, Zahlungsart>.ItemList; } // Note: uint instead of int 
    } 

Prenez garde que toutes les classes de béton générées à partir d'un type générique aura ses propres champs statiques, ils ne sont pas partagé.

+0

putain tu as raison, j'ai tellement tripoté autour du code que j'en ai posté un qui fonctionnait réellement :) – codymanix

+0

Puis-je contourner la redéfinition de ItemList dans chaque sous-classe? Sans cela, le ctor statique n'est pas appelé. Cela signifie count est 0, jusqu'à ce que j'accède au premier membre statique de la classe dérivée en question. – codymanix

+0

Vous ne pouvez pas, c'est un comportement fondamental. Les membres statiques ont un type différent, le partage n'est pas possible. Vous devez repenser cela. –

2

Comment utiliser "constructeur statique" ??

public class Zahlungsart : EnumBase<int, Zahlungsart> 
{ 
    public static readonly Zahlungsart Erlagsschein; 
    public static readonly Zahlungsart Lastschrift; 

    static Zahlungsart() 
    { 
     Erlagsschein = new Zahlungsart("Erlagsschein", 0); 
     Lastschrift = new Zahlungsart("Lastschrift", 1); 
    } 

    private Zahlungsart(string text, int value) : base(text, value) { } 
    public static new IEnumerable<Zahlungsart> ItemList { get { return EnumBase<int, Zahlungsart>.ItemList; } } 
} 
+0

Le compilateur génère automatiquement un cctor pour initialiser les membres en lecture seule. Cela ne peut faire aucune différence. –

+0

@Hans, ça peut. Un constructeur statique supprimera l'indicateur "beforefieldinit", provoquant l'exécution de tous les champs statiques lors de la première utilisation du type. Un type sans constructeur statique est marqué comme "beforefieldinit", et les champs statiques ne sont garantis que pour être initialisés avant d'être référencés, mais il n'y a aucune garantie qu'ils sont initialisés avant que d'autres codes ne soient exécutés dans ce type. http://www.yoda.arachsys.com/csharp/beforefieldinit.html – sisve

+0

Pourquoi une mauvaise réponse obtient-elle autant de points? – codymanix