Преобразование целого числа к помещенному в коробку перечислимому типу, только известному во времени выполнения

Предположите, что у нас есть перечисление:

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

Если тип известен во время компиляции, прямой бросок может использоваться для изменения между перечислимым типом и базовым типом (обычно int):

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

И упаковка этого дает поле типа Foo:

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

(и действительно, можно упаковать как Foo и распакуйте как int, или поле как int и распакуйте как Foo вполне счастливо)

Однако (проблема); если перечислимый тип только известен в вещах во время выполнения... более хитры. Это очевидно тривиально для упаковки его как int - но действительно ли я могу упаковать его как Foo? (Идеально, не используя дженериков и MakeGenericMethod, который был бы ужасен). Convert.ChangeType выдает исключение. ToString и Enum.Parse работы, но ужасно неэффективно.

Я мог посмотреть на определенные значения (Enum.GetValues или Type.GetFields), но это очень трудно для [Flags], и даже без потребовал бы возвращения к базовому типу сначала (который не так тверд, к счастью).

Но; существует ли, больше прямо к добираются от значения корректного базового типа к полю перечислимого типа, где тип только известен во времени выполнения?

42
задан Marc Gravell 17 April 2010 в 21:47
поделиться

2 ответа

Я думаю, что метод Enum.ToObject сделает то, что вы хотите.

Type type= typeof(Foo);
object o1 = Enum.ToObject(type,GetValue());
71
ответ дан 26 November 2019 в 23:43
поделиться

Просто хотел что-то добавить к ответу @ aaronb : Мне пришлось сделать именно это для некоторого кода автоматического сопоставления, и я обнаружил, что мне нужно сделать несколько проверок, чтобы заставить код работать для произвольные типы. В частности, значения NULL и перечисления, допускающие значение NULL, доставят вам головную боль.

Самый надежный код, который у меня есть на данный момент, таков:

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

Если у вас никогда не может быть типа, допускающего значение NULL, просто проигнорируйте его. :)

8
ответ дан 26 November 2019 в 23:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: