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