使用Key = Enums Name和Value = Enums值使用最佳技术创建键值对列表
在C#4.0 – 5.0中,如何创建键值对列表,其中键是枚举名称的值,值是枚举名称值。
同样在C#中,如何创建键值对列表,其中键是枚举名称,值是属性EnumName名称。
我希望有两个基于枚举名称的单独列表,以便从attribtue中检索值或人类可读的名称。
例:
public enum QATypes { [EnumMember(Value = "Black Box")] BlackBox = 10, [EnumMember(Value = "Integration Tests")] IntegrationTests = 20, [EnumMember(Value = "Acceptance Testing")] AcceptanceTesting= 30, ... }
并且第一个列表对于值看起来像这样:
{{ key:"BlackBox", value:10 }, { key:"IntegrationTests ", value:20 },{ key:"AcceptanceTesting", value:30 },...}
对于enumsmember,第二个列表看起来像这样:
{{ key:"BlackBox", value:"Black Box"}, { key:"IntegrationTests ", value:"Integration Tests"},{ key:"AcceptanceTesting", value:"Acceptance Testing"},...}
你可以使用Reflection。 试试这个(假设所有枚举成员都有一个EnumMemberAttribute
):
var qatype = typeof(QATypes); var names = qatype.GetEnumNames(); var values = qatype.GetEnumValues().Cast().ToList(); var nameValues = names.Select(n => qatype.GetMember(n)[0] .CustomAttributes.First() .NamedArguments[0].TypedValue .Value) .ToList(); var valuesList = names.Select((n, index) => new { key = n, value = values[index] }) .ToList(); var nameValuesList = names.Select((n, index) => new { key = n, value = nameValues[index] }) .ToList();
此外,由于您的问题似乎与JSON相关,如果您想要以JSON格式序列化列表,您可以使用Json.NET :
var valuesJson = JsonConvert.SerializeObject(valuesList); Console.WriteLine(valuesJson);
输出:
[ { "key": "BlackBox", "value": 10 }, { "key": "IntegrationTests", "value": 20 }, { "key": "AcceptanceTesting", "value": 30 } ]
和
var nameValuesJson = JsonConvert.SerializeObject(nameValuesList); Console.WriteLine(nameValuesJson);
哪个输出:
[ { "key": "BlackBox", "value": "Black Box" }, { "key": "IntegrationTests", "value": "Integration Tests" }, { "key": "AcceptanceTesting", "value": "Acceptance Testing" } ]
关于返回订单和exception处理的一些评论
依赖于GetEnumValues
和GetEnumNames
返回的项的顺序似乎不是一个潜在的问题,因为这两个方法在内部依赖于相同的方法:
[SecuritySafeCritical] private static void GetCachedValuesAndNames (RuntimeType enumType, out ulong[] values, out string[] names, bool getValues, bool getNames)
并最终在这个方法:
[SecurityCritical, SuppressUnmanagedCodeSecurity] [DllImport("QCall", CharSet = CharSet.Unicode)] private static extern void GetEnumValuesAndNames (RuntimeTypeHandle enumType, ObjectHandleOnStack values, ObjectHandleOnStack names, bool getValues, bool getNames);
我提供的代码段并未涵盖所有exception,它依赖于原始问题中提供的示例数据。 例如,它不检查是否存在EnumMemberAttribute
或它的Value
属性。 但这可以通过一点点努力轻松改变。
当枚举成员具有相同的值但名称不同时, Enum.GetValues
是危险的,例如:
enum { A, B = A, C }
您应该使用Enum.GetNames
,然后获取相应的值。
我有这个助手类来处理类似的事情:
public static class Enum where T : struct, IComparable, IFormattable, IConvertible { public static IEnumerable GetValues() { return (T[])Enum.GetValues(typeof(T)); } public static IEnumerable GetNames() { return Enum.GetNames(typeof(T)); } public static T Parse(string @enum) { return (T)Enum.Parse(typeof(T), @enum); } public static S GetAttribute(string @enum) where S : Attribute { return (S)typeof(T).GetMember(@enum)[0] .GetCustomAttributes(typeof(S), false) .SingleOrDefault(); } }
这是完全通用的,因此您需要更多的打字来打电话。 现在我可以做:
var first = Enum.GetNames().ToDictionary(x => x, x => (int)Enum .Parse(x)); var second = first.ToDictionary(x => x.Key, x => Enum .GetAttribute(x.Key).Value);
您可以在合适的命名空间中创建自己的扩展方法,您无需传递枚举属性类型参数,以方便调用。
此外,您可以使辅助类非静态,这将有助于您更好地进行类型推断, 从而缩短调用代码 。 应该是这样的:
var helper = new Enum(); var first = helper.GetNames().ToDictionary(x => x, x => (int)helper.Parse(x)); var second = first.ToDictionary(x => x.Key, x => helper.GetAttribute(x.Key).Value);
对于第一个问题:
var list = new List>(); foreach(var e in Enum.GetValues(typeof(QATypes))) { list.Add(new KeyValuePair(e.ToString(), (int)e)); }
对于第二个问题:
var list = new List>(); foreach(var e in typeof(QATypes).GetFields()) { var attribute = e.GetCustomAttributes(typeof(EnumMemberAttribute)) .FirstOrDefault() as EnumMemberAttribute; if(attribute != null) { list.Add(new KeyValuePair(e.Name, attribute.Value)); } }