Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to Cast Enum to Int

I have the following code. I need it to create a List of KeyValuePair<string, string> with the name and value of each enum value in the specified enum type.

public static List<KeyValuePair<string, string>> GetEnumList<TEnum>() where TEnum : struct
{
    if (!typeof(TEnum).IsEnum)
        throw new ArgumentException("Type must be an enumeration");
    List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
    foreach (TEnum e in Enum.GetValues(typeof(TEnum)))
        list.Add(new KeyValuePair<string, string>(e.ToString(), ((int)e).ToString()));
    return list;
}

However, the expression ((int)e).ToString() generates the following error.

Cannot convert type 'TEnum' to 'int'

I'm just trying to cast an enum instance to an integer. Can anyone tell me why this won't work?

EDIT:

I tried this version:

enum Fruit : short
{
    Apple,
    Banana,
    Orange,
    Pear,
    Plum,
}

void Main()
{
    foreach (var x in EnumHelper.GetEnumList<Fruit>())
        Console.WriteLine("{0}={1}", x.Value, x.Key);
}

public static List<KeyValuePair<string, string>> GetEnumList<TEnum>() where TEnum : struct
{
    if (!typeof(TEnum).IsEnum)
        throw new ArgumentException("Type must be an enumeration");
    List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
    foreach (TEnum e in Enum.GetValues(typeof(TEnum)))
    {
        list.Add(new KeyValuePair<string, string>(e.ToString(), ((int)(dynamic)e).ToString()));
    }
    return list;
}

But this gives me the error:

Cannot convert type 'System.Enum' to 'int'

like image 208
Jonathan Wood Avatar asked Dec 15 '22 10:12

Jonathan Wood


2 Answers

TEnum is - per constraint - a struct. It isn't guaranteed to be an enum.

However, because you are enforcing that constraint at runtime, you can utilize the fact the each enum implements IConvertible:

foreach (IConvertible e in Enum.GetValues(typeof(TEnum)))
{
    list.Add(new KeyValuePair<string, string>(
        e.ToString(),
        e.ToType(
            Enum.GetUnderlyingType(typeof(TEnum)),
            CultureInfo.CurrentCulture).ToString()));
}

Other approaches which all have downsides are:

You can first cast to object and then to int.

Please note that this will fail at runtime if the underlying type of the enum is anything other than int.

This can be overcome by casting to dynamic before casting to int:

((int)(dynamic)e).ToString()

However, this again has some problems:

If the enum is of type long, ulong or uint it will return incorrect values. You can reduce the problem by casting to ulong instead of int but that will still return invalid values for negative enum values.

like image 169
Daniel Hilgarth Avatar answered Dec 27 '22 22:12

Daniel Hilgarth


The only safe way to do this, without nowing the base type, is to use the methods created for it! The methods inside the Enum-class. Even you could try to make use of the IConvertable interface.

// Get underlying type, like int, ulong, etc.
Type underlyingType = Enum.GetUnderlyingType(typeof(T); 
// Convert the enum to that type.
object underlyingValue = e.ToType(underlyingType, null);
// Convert that value to string. 
string s = underlyingValue.ToString(); 

Or in short:

string s = e.ToType(Enum.GetUnderlyingType(typeof(T)), null).ToString();

You can implement it in your code like this:

public static List<KeyValuePair<string, string>> GetEnumList<TEnum>() 
          where TEnum : struct, IConvertible
{
    if (!typeof(TEnum).IsEnum)
        throw new ArgumentException("Type must be an enumeration");
    List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
    foreach (TEnum e in Enum.GetValues(typeof(TEnum)))
    {
        list.Add(new KeyValuePair<string, string>
        (
            e.ToString(), 
            e.ToType(Enum.GetUnderlyingType(typeof(TEnum)), null).ToString()
        ));
    }
    return list;
}

If you do not want to use IConvertable, try to use the Convert class:

string s = Convert.ChangeType(e, Enum.GetUnderlyingType(typeof(TEnum))).ToString();
like image 36
Martin Mulder Avatar answered Dec 28 '22 00:12

Martin Mulder