Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing static fields in C# for use in enum pattern

My question is actually about a way to work around how C# initializes static fields. I need to do this, in my attempt to duplicate a Java style enum. The following is an example of the code that shows the problem:

A base class for all my enums to inherit from

public class EnumBase
{
    private int _val;
    private string _description;

    protected static Dictionary<int, EnumBase> ValueMap = new Dictionary<int, EnumBase>();

    public EnumBase(int v, string desc)
    {
        _description = desc;
        _val = v;
        ValueMap.Add(_val, this);
    }

    public static EnumBase ValueOf(int i)
    {
        return ValueMap[i];
    }

    public static IEnumerable<EnumBase> Values { get { return ValueMap.Values; } }

    public override string ToString()
    {
        return string.Format("MyEnum({0})", _val);
    }
}

A sample of an enumerated set:

public sealed class Colors : EnumBase
{
    public static readonly Colors Red    = new Colors(0, "Red");
    public static readonly Colors Green  = new Colors(1, "Green");
    public static readonly Colors Blue   = new Colors(2, "Blue");
    public static readonly Colors Yellow = new Colors(3, "Yellow");

    public Colors(int v, string d) : base(v,d) {}
}

This is where the problem is:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("color value of 1 is " + Colors.ValueOf(2)); //fails here
    }
}

The above code fails because EnumBase.ValueMap contains zero items, because none of the constructors for Color have been called yet.

It seems like this shouldn't be that hard to do, it is possible in Java, I feel like I must be missing something here?

like image 731
Sheamus Avatar asked Dec 11 '25 16:12

Sheamus


1 Answers

That pattern basically isn't going to work. Having a single dictionary isn't going to be a good idea, either - I suspect you want to make your EnumBase abstract and generic:

public abstract class EnumBase<T> where T : EnumBase<T>

That could then have a protected static member which can be effectively "published" through each derived class:

public abstract class EnumBase<T> where T : EnumBase<T>
{
    protected static T ValueOfImpl(int value)
    {
        ...
    }
}

public class Color : EnumBase<Color>
{
    // static fields

    // Force initialization on any access, not just on field access
    static Color() {}

    // Each derived class would have this.
    public static Color ValueOf(int value)
    {
        return ValueOfImpl(value);
    }
}

This then forces you to access the Color class itself... at which point the fields will be initialized, due to the static initializer.

There are quite a few things to be done to make all of this work, unfortunately :(

like image 50
Jon Skeet Avatar answered Dec 14 '25 05:12

Jon Skeet