使用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处理的一些评论

依赖于GetEnumValuesGetEnumNames返回的项的顺序似乎不是一个潜在的问题,因为这两个方法在内部依赖于相同的方法:

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