简体   繁体   中英

Enum to dictionary

I want to implement an extension method which converts an enum to a dictionary:

public static Dictionary<int, string> ToDictionary(this Enum @enum)
{
    Type type1 = @enum.GetType();
    return Enum.GetValues(type1).Cast<type1>()
        //.OfType<typeof(@enum)>()
        .ToDictionary(e => Enum.GetName(@enum.GetType(), e));
}

Why it doesn't compile?

An error:

"The type or namespace name 'type1' could not be found (are you missing a using directive or an assembly reference?)"

Jon Skeet has written everything you need ;)

But here you have your code that is working:

public static Dictionary<int, string> ToDictionary(this Enum @enum)
{
  var type = @enum.GetType();
  return Enum.GetValues(type).Cast<int>().ToDictionary(e => e, e => Enum.GetName(type, e));
}

Well, you're trying to use a variable of type Type as a generic type argument. You can't do that with generics, which are about compile-time types.

You can do it with reflection, but it would be better to make it a generic method. Unfortunately you can't constrain a generic type parameter to be an enum, although I have some hacks to work around that in Unconstrained Melody .

Failing that, you could use just a struct type constraint for a generic method which would be a good start.

Now, the next problem is that you're trying to get a Dictionary<int, string> - but the values of an enum aren't int values. They might be convertable to int values, but they aren't there immediately. You could use Convert.ToInt32 to do that, but you would have to do something .

Finally (for the moment) what would you expect to happen with an enum using a uint or long underlying type?

You can't use type1 as a generic parameter, because it is a variable, not a type.

The following code does something similar to what your code shows:

public static Dictionary<string, TEnum> ToDictionary<TEnum>()
    where TEnum : struct
{
    if (!typeof(TEnum).IsEnum)
        throw new ArgumentException("Type must be an enumeration");
    return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().
            ToDictionary(e => Enum.GetName(typeof(TEnum), e));
}

Use it like this:

ToDictionary<Colors>()

But I am not really sure, this is, what you expected?

Additionally, it has one problem: You can pass any struct, not just enums and this will result in a runtime exception. See Jon's answer for more details about that.

Based on Daniel's solution :

public static SelectList ToSelectList<TEnum>(this HtmlHelper h) where TEnum : struct
{
    return new SelectList(FortunaExtension.ToDictionary<TEnum>(), "Key", "Value");
}

Here is the extension method I use to convert enumerations. The only difference is that I am returning IEnumerbale<KeyValuePair<int, int>> for my purpose:

public static IEnumerable<KeyValuePair<int, string>> ToListOfKeyValuePairs<TEnum>(this TEnum enumeration) where TEnum : struct
{
    return from TEnum e in Enum.GetValues(typeof(TEnum))
            select new KeyValuePair<int, string>
                (
                    (int)Enum.Parse(typeof(TEnum), e.ToString()),
                    Regex.Replace(e.ToString(), "[A-Z]", x => string.Concat(" ", x.Value[0])).Trim()
                );
}

It also adds spaces for the value.

Example:

enum Province
{
    BritishColumbia = 0,
    Ontario = 1
}

Usage:

<select>
<% foreach(var item in Province.BritishColumbia.ToListOfKeyValuePairs()){ %>
    <option value="<%=item.Key %>"><%=item.Value %></option>
<% } %>
</select>

Output:

<select>
    <option value="0">British Columbia</option>
    <option value="1">Ontario</option>
</select>

Though @Paul Ruane is correct I have found this to be a very useful extension method. It's not a perfect world.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM