Reputation: 53
In C# 4.0 - 5.0 how do you create a list of key value pairs where the key is the enums name's value and the value is the enums name value.
Also in C# how do you create a list of key value pairs where the key is the enums name and the value is the attributes EnumName name.
I want to have two seperate list based on the enum's name in order to retrieve the value or the human readable name from the attribtue.
example:
public enum QATypes
{
[EnumMember(Value = "Black Box")]
BlackBox = 10,
[EnumMember(Value = "Integration Tests")]
IntegrationTests = 20,
[EnumMember(Value = "Acceptance Testing")]
AcceptanceTesting= 30,
...
}
and the first list would look like this for values:
{{ key:"BlackBox", value:10 }, { key:"IntegrationTests ", value:20 },{ key:"AcceptanceTesting", value:30 },...}
and the second list would look like this for enumsmember:
{{ key:"BlackBox", value:"Black Box"}, { key:"IntegrationTests ", value:"Integration Tests"},{ key:"AcceptanceTesting", value:"Acceptance Testing"},...}
Upvotes: 3
Views: 11762
Reputation: 73173
Enum.GetValues
is dangerous when you have enum members with same values but different names, like:
enum { A, B = A, C }
You should use Enum.GetNames
and then get the corresponding values.
I have this helper class to deal with similar things:
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();
}
}
This is fully generic, so you need a bit more typing to call. Now I can do:
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);
You can create your own extension method in a suitable namespace where you need not pass the enum attribute type argument, to ease calling.
Also you can make the helper class non-static which will help you with type-inference better and thus make calling code shorter. Should look like:
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);
Upvotes: 3
Reputation: 32561
You may use Reflection. Try this (assuming that all the enum members have an 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();
Further on, since your question seems to be JSON - related, if you want to serialize the lists in the JSON format, you may use Json.NET:
var valuesJson = JsonConvert.SerializeObject(valuesList);
Console.WriteLine(valuesJson);
Output:
[
{
"key": "BlackBox",
"value": 10
},
{
"key": "IntegrationTests",
"value": 20
},
{
"key": "AcceptanceTesting",
"value": 30
}
]
And
var nameValuesJson = JsonConvert.SerializeObject(nameValuesList);
Console.WriteLine(nameValuesJson);
Which outputs:
[
{
"key": "BlackBox",
"value": "Black Box"
},
{
"key": "IntegrationTests",
"value": "Integration Tests"
},
{
"key": "AcceptanceTesting",
"value": "Acceptance Testing"
}
]
Some remarks about the returned order and exception handling
Relying on the order of the items returned by the GetEnumValues
and GetEnumNames
seems not to be a potential issue, as both these methods rely internally on the same method:
[SecuritySafeCritical]
private static void GetCachedValuesAndNames
(RuntimeType enumType,
out ulong[] values,
out string[] names,
bool getValues,
bool getNames)
and ultimately on this method:
[SecurityCritical, SuppressUnmanagedCodeSecurity]
[DllImport("QCall", CharSet = CharSet.Unicode)]
private static extern void GetEnumValuesAndNames
(RuntimeTypeHandle enumType,
ObjectHandleOnStack values,
ObjectHandleOnStack names,
bool getValues,
bool getNames);
The code snippet I provided doesn't cover all exceptions, it relies on the sample data provided in the original question. For example, it doesn't check for the existence of the EnumMemberAttribute
or it's Value
property. But this can be easily changed with a little amount of effort.
Upvotes: 4
Reputation: 15941
For the first question:
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));
}
for the second question:
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));
}
}
Upvotes: 2