初始化c#中的静态字段以用于枚举模式
本文关键字:用于 枚举 模式 字段 静态 初始化 | 更新日期: 2023-09-27 18:09:38
我的问题实际上是关于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");
}