Предположите, что у нас есть перечисление:
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]
, и даже без потребовал бы возвращения к базовому типу сначала (который не так тверд, к счастью).
Но; существует ли, больше прямо к добираются от значения корректного базового типа к полю перечислимого типа, где тип только известен во времени выполнения?
Я думаю, что метод Enum.ToObject
сделает то, что вы хотите.
Type type= typeof(Foo);
object o1 = Enum.ToObject(type,GetValue());
Просто хотел что-то добавить к ответу @ 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, просто проигнорируйте его. :)