47

I'm writing an utility function that gets a integer from the database and returns a typed enum to the application.

Here is what I tried to do (note I pass in a data reader and column name instead of the int in my real function):

public static T GetEnum<T>(int enumAsInt)
{
    Type enumType = typeof(T);

    Enum value = (Enum)Enum.ToObject(enumType, enumAsInt);
    if (Enum.IsDefined(enumType, value) == false)
    {
        throw new NotSupportedException("Unable to convert value from database to the type: " + enumType.ToString());
    }

    return (T)value;
}

But it won't let me cast (T)value saying:

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

Also I've read quite a bit of mixed reviews about using Enum.IsDefined. Performance wise it sounds very poor. How else can I guarantee a valid value?

Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137
Justin
  • 10,667
  • 15
  • 58
  • 79
  • Note that if the case had been other way around, say, you have to do `(Enum)value` and you get `Cannot convert type 'T' to 'System.Enum'`, you could merely do an `as` cast, like `value as Enum`. – nawfal Jun 09 '13 at 13:07
  • 1
    Not true (at least in my case), you get the old 'The as operator must be used with a reference or nullable type ('Foo.bar' is a non-nullable value type) error. – keithl8041 Feb 10 '14 at 12:54

3 Answers3

72

Like this:

return (T)(object)value;
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • 3
    It would be better to initially declare `value` as an `object`. – João Angelo Jul 15 '10 at 23:13
  • Thanks that seems to compile. I don't understand the reason for the error then? Bonus points if you can explain why in the interest of learning:) – Justin Jul 15 '10 at 23:20
  • 2
    The compiler doesn't realize that `T` is a enum type. As far as it is aware, `T` might be `DateTime`. Therefore, you cannot cast directly from any type other than `object` to `T`. – SLaks Jul 15 '10 at 23:23
  • I did try to constrain T in the method signature with "where T : Enum". But the compiler tells me Constraint cannot be special class 'System.Enum'. – Justin Jul 15 '10 at 23:27
  • 3
    @Justin: [Yes; this is an annoying and unnecessary limitation](http://stackoverflow.com/questions/1331739/enum-type-constraints-in-c/1416660#1416660) – SLaks Jul 15 '10 at 23:51
  • 1
    Can't this be done without box-unbox? May be using this `__makeref` thing – AgentFire May 02 '15 at 20:57
20

Change this:

Enum value = (Enum)Enum.ToObject(enumType, enumAsInt);

to this:

T value = (T)Enum.ToObject(enumType, enumAsInt);

and remove the cast :)

porges
  • 30,133
  • 4
  • 83
  • 114
2

For information, using the generic constraint Enum is available from C# 7.3 and greater.

Eli
  • 414
  • 5
  • 10