初始化c#中的静态字段以用于枚举模式



我的问题实际上是关于c#如何初始化静态字段的方法。我需要这样做,在我试图复制Java风格的枚举。下面是显示该问题的代码示例:

继承的所有枚举的基类
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);
    }
}

枚举集的示例:

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) {}
}

这就是问题所在:

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

上面的代码失败是因为EnumBase。ValueMap不包含任何项,因为Color的任何构造函数都还没有被调用。

这似乎不应该很难做到,在Java中是可能的,我觉得我一定错过了什么?

这个模式基本上是行不通的。拥有一个单一的字典也不是一个好主意——我怀疑你想让你的EnumBase抽象和通用:

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

可以有一个受保护的静态成员,可以通过每个派生类有效地"发布":

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

然后强制您访问Color类本身…此时,由于静态初始化器,字段将被初始化。

不幸的是,要使所有这些工作完成,需要做很多事情:(

我相信你想用代码表达的意思很简单:

public enum Colors
    {
        [Description("Red")]
        Red = 0,
        [Description("Green")]
        Green = 1,
        [Description("Blue")]
        Blue = 2
        //etc...
    }

您可以使用反射轻松地读取Description属性。如果需要,您甚至可以为Colors枚举创建扩展方法,并实现与ValueOf类似的扩展方法

您错过了静态成员的意义。静态成员是类型的成员,而不是实例。

当你调用Colors.ValueOf()时,你只访问类型,该类型的实例还没有创建——实例构造函数根本不会被调用。

您可以为Color枚举创建一个扩展方法,如果您只是想能够定义一些行为。您可以简单地从一个值的int基数进行强制转换,从而获得枚举:

public enum Color { Red = 0, Green = 1, Blue = 2, Yellow = 3 }
public static class ColorExtensions
{
    public static string GetString(this Color color)
    {
        return string.Format("MyEnum({0})", color);
    }
}
Console.WriteLine("color value of 1 is " + ((Color)1).GetString());

您还可以在System.Enum类(http://msdn.microsoft.com/en-us/library/system.enum.aspx)中找到许多有用的方法。有一些方法可以解析string或获取所有可能的enum值的集合。

这是可以做到的,而且实际上非常有用。在设置变量和动态搜索时,您可以获得类型安全。我希望在子类中看到更少的代码,但不管怎样,它工作得很好。您还可以在此基础上进行扩展,增加EnumBase中的字段数量,还可以重写操作符和ToString方法等。你也可以加入更多的泛型。这是打了类固醇的Enums。

编辑:阅读条目底部

EnumBase:

public class EnumBase
{
    public int Val { get; private set; }
    public string Description { get; private set; }
    private static readonly Dictionary<int, EnumBase> ValueMap = new Dictionary<int, EnumBase>();
    protected EnumBase(int v, string desc)
    {
        Description = desc;
        Val = v;
    }
    protected static void BuildDictionary<T>()
    {
        var fields = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static);
        foreach (var field in fields)
        {
            ValueMap.Add(((EnumBase)field.GetValue(null)).Val, (EnumBase)field.GetValue(null));
        }
    }
    public static EnumBase ValueOf(int i)
    {
        return ValueMap[i];
    }
}

颜色:

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)
    {
    }
    static Colors()
    {
        BuildDictionary<Colors>();
    }
}

用法:

//example of type safety
var i = Colors.Blue.Val;
//example of dynamic search
Console.WriteLine(Colors.ValueOf(1).Description);

编辑:

上面的代码不能工作,如果你从EnumBase继承了不止一次(这是一个巨大的问题)。静态方法不被继承,即所有子类只会向静态基类Dictionary添加更多记录。

如果用例足够强大,您可以重用代码,而不是尝试使用继承:

public sealed class Colors 
{
    public int Val { get; private set; }
    public string Description { get; private set; }
    private static readonly Dictionary<int, Colors> ValueMap = new Dictionary<int, Colors>();
    static Colors()
    {
        BuildDictionary<Colors>();
    }
    private static void BuildDictionary<T>()
    {
        var fields = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static);
        foreach (var field in fields)
        {
            ValueMap.Add(((Colors)field.GetValue(null)).Val, (Colors)field.GetValue(null));
        }
    }
    public static Colors ValueOf(int i)
    {
        return ValueMap[i];
    }
    private Colors(int v, string desc)
    {
        Description = desc;
        Val = v;
    }
    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");
}

最新更新