2010-04-17 5 views
34

Wyobraź mamy ENUM:Konwersja liczbę całkowitą do pudełkowej typu enum znany tylko w czasie wykonywania

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

Jeśli typ jest znany w czasie kompilacji, bezpośredni obsada może być wykorzystana do zmiany pomiędzy enum- Rodzaj i typ bazowy (zazwyczaj int):

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

i boks daje to pole typu Foo:

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

(i rzeczywiście można Pole jako Foo i unbox jako int lub pudełko jako int i unbox jak Foo dość szczęśliwie)

Jednak (problem); jeśli typ wyliczeniowy jest znany tylko podczas uruchamiania, rzeczy są ... trudniejsze. Oczywistym jest, że jest to dość banalne, aby zapisać go jako int - ale czy mogę go ustawić jako Foo? (Idealnie bez użycia generycznych i MakeGenericMethod, co byłoby brzydkie). Convert.ChangeType zgłasza wyjątek. ToString i Enum.Parse działa, ale jest strasznie nieskuteczne.

mogłem patrzeć na określonych wartościach (Enum.GetValues lub Type.GetFields), ale to jest bardzo trudne dla [Flags], a nawet bez wymagałoby wracając do bazowego typu pierwszy (który nie jest tak trudne, na szczęście).

Ale; czy jest bardziej bezpośredni, aby uzyskać od wartości prawidłowego typu bazowego do pola typu enum, gdzie typ jest znany tylko w czasie wykonywania?

Odpowiedz

60

Myślę, że metoda Enum.ToObject zrobi to, co chcesz.

Type type= typeof(Foo); 
object o1 = Enum.ToObject(type,GetValue()); 
+2

W jaki sposób | $ (* i% $ (brakowało mi tego!) Dzięki, to jest dokładnie to, czego chcę –

+3

Łatwo przegapić Wydaje się, że to straszna nazwa metody. Coś takiego jak 'Enum.FromValue' może mieć Było lepiej –

8

Chciałem tylko dodać coś do @aaronb's answer: Musiałem zrobić to bardzo rzeczą dla niektórych kodu automatycznego mapowania i okazało się, że muszę zrobić kilka kontroli w celu dokonania prac kodu dla dowolnych typów. W szczególności wartości zerowe i wyliczenia zerowe dają ból głowy.

Najbardziej niezawodny kod mam w tej chwili jest tak:

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

Jeśli nigdy nie może mieć typ zerowalne potem po prostu zignorować. :)

+0

Cenne myśli, ale w rzeczywistości już zdjąłem takie rzeczy, jak 'Nullable ', 'List ' itp. przed tym –

+0

'Nullable.GetUnderlyingType' może być trochę prostsze niż kontrola ogólnych argumentów. – Craig

Powiązane problemy