在C#中初始化静态字段以在枚举模式中使用

时间:2011-09-26 21:34:08

标签: c# initialization enumeration static-members

我的问题实际上是关于如何解决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中有可能,我觉得我必须在这里遗漏一些东西?

4 个答案:

答案 0 :(得分:6)

这种模式基本上不起作用。拥有一个字典也不是一个好主意 - 我怀疑你想要使你的EnumBase抽象和通用:

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

然后可以有一个 protected 静态成员,可以通过每个派生类有效地“发布”:

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类本身......由于静态初始化程序,字段将被初始化。

不幸的是,要做好所有这些工作还有很多工作要做:(

答案 1 :(得分:2)

我相信你在代码中所说的就是:

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

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

答案 2 :(得分:1)

你错过了静态成员的观点。静态成员是类型的成员,而不是实例。

当您调用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值的集合。

答案 3 :(得分:0)

这可以做到,而且实际上非常有用。设置变量时,您可以获得类型安全性以及动态搜索的能力。我更喜欢在子类中看到更少的代码,但是,它运行良好。您还可以扩展它并增加EnumBase中的字段数量,并覆盖运算符和ToString方法等。您还可以将更多泛型放入混合中。它是关于类固醇的枚举物。

已编辑:阅读条目底部

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

}