Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting an integer to a boxed enum type only known at runtime

Imagine we have an enum:

enum Foo { A=1,B=2,C=3 }

If the type is known at compile-time, a direct cast can be used to change between the enum-type and the underlying type (usually int):

static int GetValue() { return 2; }
...
Foo foo = (Foo)GetValue(); // becomes Foo.B

And boxing this gives a box of type Foo:

object o1 = foo;
Console.WriteLine(o1.GetType().Name); // writes Foo

(and indeed, you can box as Foo and unbox as int, or box as int and unbox as Foo quite happily)

However (the problem); if the enum type is only known at runtime things are... trickier. It is obviously trivial to box it as an int - but can I box it as Foo? (Ideally without using generics and MakeGenericMethod, which would be ugly). Convert.ChangeType throws an exception. ToString and Enum.Parse works, but is horribly inefficient.

I could look at the defined values (Enum.GetValues or Type.GetFields), but that is very hard for [Flags], and even without would require getting back to the underlying-type first (which isn't as hard, thankfully).

But; is there a more direct to get from a value of the correct underlying-type to a box of the enum-type, where the type is only known at runtime?

like image 682
Marc Gravell Avatar asked Apr 17 '10 21:04

Marc Gravell


2 Answers

I think the Enum.ToObject method will do what you want.

Type type= typeof(Foo);
object o1 = Enum.ToObject(type,GetValue());
like image 153
aaronb Avatar answered Oct 12 '22 14:10

aaronb


Just wanted to add something to @aaronb's answer: I had to do this very thing for some auto-mapping code and found out that I needed to do several checks in order to make the code work for arbitrary types. In particular, null values and nullable enums will give you headaches.

The most foolproof code I have at the moment is this:

static object CastBoxedValue(object value, Type destType)
{
    if (value == null)
        return value;

    Type enumType = GetEnumType(destType);
    if (enumType != null)
        return Enum.ToObject(enumType, value);

    return value;
}

private static Type GetEnumType(Type type)
{
    if (type.IsEnum)
        return type;

    if (type.IsGenericType)
    {
        var genericDef = type.GetGenericTypeDefinition();
        if (genericDef == typeof(Nullable<>))
        {
            var genericArgs = type.GetGenericArguments();
            return (genericArgs[0].IsEnum) ? genericArgs[0] : null;
        }
    }
    return null;
}

If you can never have a nullable type then just ignore this. :)

like image 23
Aaronaught Avatar answered Oct 12 '22 13:10

Aaronaught