Преобразование целого числа в упакованный тип enum, известный только во время выполнения - PullRequest
40 голосов
/ 18 апреля 2010

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

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

Если тип известен во время компиляции, прямое приведение может использоваться для переключения между типом enum и базовым типом (обычно 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 довольно счастливо)

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

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

Но; Есть ли более прямой способ получить значение правильного базового типа в поле типа enum, где этот тип известен только во время выполнения?

Ответы [ 2 ]

70 голосов
/ 18 апреля 2010

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

Type type= typeof(Foo);
object o1 = Enum.ToObject(type,GetValue());
8 голосов
/ 18 апреля 2010

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

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

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, тогда простоигнорируй это.:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...