Search code examples
c#.netgenericsstatic-constructor

Strange behaviour with static fields


I am trying to get a custom enum class working which should enable me to create enums with user friendly identifiers and an arbitrary associated value. so far so good:

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

And now my problem:

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

The following statement gives me 0, instead of 2. The problem is due to beforefieldinit, I think. I could work around this by calling some method of the specific enum directly which would force the static fields to load, but this is not the best solution, I think.

Hint: please do not propose some kind of [UserfriendlyName()]-attribute for enum here, I already know them.

EDIT Thanks, hans. I had indeed a typo in my own code, calling the wrong generic specialisation.

Now my question is, can I get rid of the redefinition of ItemList in each subclass, but it seems this is necessary to to get the static fields initialized.


Solution

  • Your code doesn't repro the problem. But you will get a repro if you change the property like this:

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

    Beware that every concrete class generated from a generic type will have its own static fields, they are not shared.