29

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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Alexandre
  • 13,030
  • 35
  • 114
  • 173

5 Answers5

54

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));
}
Community
  • 1
  • 1
Rafal Spacjer
  • 4,838
  • 2
  • 26
  • 34
  • 1
    You can simplify it slightly by writing `Cast` instead of `Cast`, because then you can omit the cast from object to int in the first lambda-expression. – Elian Ebbing Mar 31 '11 at 13:14
  • 2
    This isn't going to work for all Enum underlying types. Also check that `typeof(int) == Enum.GetUnderlyingType(type)`. – Martin Thomson Jul 12 '13 at 19:23
  • 1
    If you're using the lowercase type of `enum`, use `typeof(@enum)` instead of `@enum.GetType()`. – Andrew Feb 12 '14 at 14:40
  • 3
    Can you show an example usage? this isn't showing up for me. – Chazt3n Jan 26 '15 at 16:48
  • public enum SomeEnum { A, B, C } and the usage: var d = SomeEnum.A.ToDictionary(); – Rafal Spacjer Jan 27 '15 at 06:51
  • @Rafal So your saying you reference one of the enum values and then call the function against it? Doesnt the function take a parameter of (this Enum @enum)? – JohnnyBizzle Jul 10 '15 at 14:52
  • @JohnnyBizzle yes, the method takes enum value, so you need to pass one. Otherwise you can't say that method takes enum - it could take type, but then it would be any type. – Rafal Spacjer Jul 10 '15 at 23:07
13

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?

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
5

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • It's not what I expect. I want to use extension method. – Alexandre Mar 31 '11 at 13:09
  • Show a code sample of your usage and the expected output. (Because it doesn't seem to make sense to invoke this as an extension method) – Daniel Hilgarth Mar 31 '11 at 13:10
  • 1
    @Alex Maslakov: an extension method is not really appropriate here as you are building a dictionary from the data about the enum that is available statically (i.e. it is data in the enum type definition rather than using the properties of a particular enum value). Extension methods operate on an instance of a type. – Paul Ruane Mar 31 '11 at 13:15
2

Based on Daniel's solution:

public static SelectList ToSelectList<TEnum>(this HtmlHelper h) where TEnum : struct
{
    return new SelectList(FortunaExtension.ToDictionary<TEnum>(), "Key", "Value");
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
1

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Craig
  • 6,869
  • 3
  • 32
  • 52