Alexandre
Alexandre

Reputation: 13328

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?)"

Upvotes: 29

Views: 19872

Answers (5)

Claudio Mertz
Claudio Mertz

Reputation: 21

Based on Daniel's solution:

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

Upvotes: 2

Craig
Craig

Reputation: 7076

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.

Upvotes: 1

Daniel Hilgarth
Daniel Hilgarth

Reputation: 174457

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.

Upvotes: 5

Rafal Spacjer
Rafal Spacjer

Reputation: 4918

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

Upvotes: 54

Jon Skeet
Jon Skeet

Reputation: 1503759

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?

Upvotes: 13

Related Questions