2010-12-08 3 views
2

Я пытаюсь создать пользовательский класс enum, который должен позволить мне создавать перечисления с удобными идентификаторами и произвольным связанным значением. до сих пор так хорошо:Странное поведение со статическими полями

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; } } 
} 

И теперь моя проблема:

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

Следующее утверждение дает мне 0 вместо 2. Проблема обусловлена ​​beforefieldinit, я думаю. Я мог бы обойти это, вызвав какой-то метод специфического перечисления напрямую, который заставил бы статические поля загружаться, но это не лучшее решение, я думаю.

Подсказка: пожалуйста, не предлагайте какой-либо атрибут [UserfriendlyName()] - для перечисления здесь, я уже знаю их.

EDIT Спасибо, hans. У меня действительно была опечатка в моем собственном коде, назвав неправильную общую специализацию.

Теперь мой вопрос: могу ли я избавиться от переопределения ItemList в каждом подклассе, но, похоже, это необходимо для инициализации статических полей.

+0

Когда я запускаю этот точный код, я получаю «2» в качестве вывода. – cdhowie 2010-12-08 17:27:08

ответ

1

Ваш код не воспроизводит проблему. Но вы получите репро, если вы измените свойство как это:

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

Берегись, что каждый конкретный класс, порожденный от общего типа будет иметь свои собственные статические поля, они не совместно.

2

Как насчет использования «статического конструктора»?

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

Компилятор уже автоматически генерирует cctor для инициализации членов readonly. Это не может иметь никакого значения. – 2010-12-08 18:21:35

+0

@ Может, он может. Статический конструктор удаляет флаг «beforefieldinit», заставляя все статические поля выполняться, когда тип используется впервые. Тип без статического конструктора помечен как «beforefieldinit», и статические поля гарантированно будут инициализироваться только до того, как они будут указаны вначале, но нет никакой гарантии, что они будут инициализированы до того, как в этом типе будет выполнен другой код. http://www.yoda.arachsys.com/csharp/beforefieldinit.html – sisve 2010-12-08 19:41:54

Смежные вопросы