在C#4.0 - 5.0中,如何创建一个键值对列表,其中键是枚举名称的值,值是枚举名称值。
同样在C#中,如何创建一个键值对列表,其中键是枚举名称,值是属性EnumName name。
我想根据枚举的名称设置两个单独的列表,以便从属性中检索值或人类可读的名称。
示例:
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"},...}
答案 0 :(得分:3)
您可以使用反射。试试这个(假设所有枚举成员都有EnumMemberAttribute
):
var qatype = typeof(QATypes);
var names = qatype.GetEnumNames();
var values = qatype.GetEnumValues().Cast<int>().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"
}
]
有关退回订单和异常处理的一些评论
依赖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);
我提供的代码段并未涵盖所有异常,它依赖于原始问题中提供的示例数据。例如,它不检查是否存在EnumMemberAttribute
或它的Value
属性。但这可以通过一些努力轻松改变。
答案 1 :(得分:3)
Enum.GetValues
会很危险,例如:
enum { A, B = A, C }
您应该使用Enum.GetNames
,然后获取相应的值。
我有这个帮助类来处理类似的事情:
public static class Enum<T> where T : struct, IComparable, IFormattable, IConvertible
{
public static IEnumerable<T> GetValues()
{
return (T[])Enum.GetValues(typeof(T));
}
public static IEnumerable<string> GetNames()
{
return Enum.GetNames(typeof(T));
}
public static T Parse(string @enum)
{
return (T)Enum.Parse(typeof(T), @enum);
}
public static S GetAttribute<S>(string @enum) where S : Attribute
{
return (S)typeof(T).GetMember(@enum)[0]
.GetCustomAttributes(typeof(S), false)
.SingleOrDefault();
}
}
这是完全通用的,因此您需要更多的打字来打电话。现在我可以做:
var first = Enum<QATypes>.GetNames().ToDictionary(x => x, x => (int)Enum<QATypes>.Parse(x));
var second = first.ToDictionary(x => x.Key, x => Enum<QATypes>.GetAttribute<EnumMemberAttribute>(x.Key).Value);
您可以在合适的命名空间中创建自己的扩展方法,您无需传递枚举属性类型参数,以便于调用。
此外,您可以使辅助类非静态,这将有助于您更好地使用类型推断,并且从而使调用代码更短。应该是这样的:
var helper = new Enum<QATypes>();
var first = helper.GetNames().ToDictionary(x => x, x => (int)helper.Parse(x));
var second = first.ToDictionary(x => x.Key, x => helper.GetAttribute<EnumMemberAttribute>(x.Key).Value);
答案 2 :(得分:0)
对于第一个问题:
var list = new List<KeyValuePair<string,int>>();
foreach(var e in Enum.GetValues(typeof(QATypes)))
{
list.Add(new KeyValuePair<string,int>(e.ToString(), (int)e));
}
第二个问题:
var list = new List<KeyValuePair<string,string>>();
foreach(var e in typeof(QATypes).GetFields())
{
var attribute = e.GetCustomAttributes(typeof(EnumMemberAttribute))
.FirstOrDefault() as EnumMemberAttribute;
if(attribute != null)
{
list.Add(new KeyValuePair<string,string>(e.Name, attribute.Value));
}
}