2012-04-30 10 views
50

Podobny do Cast int to enum in C#, ale moje wyliczenie jest parametrem Typowy. Jaki jest najlepszy sposób na obsłużenie tego?Odleć Int do ogólnego wyliczenia w języku C#

przykład:

private T ConvertEnum<T>(int i) where T : struct, IConvertible 
{ 
    return (T)i; 
} 

generuje błąd kompilatora Cannot convert type 'int' to 'T'

Pełny kod jest następujący, wartość ta może zawierać int lub null.

private int? TryParseInt(string value) 
{ 
    var i = 0; 
    if (!int.TryParse(value, out i)) 
    { 
     return null; 
    } 
    return i; 
} 

private T? TryParseEnum<T>(string value) where T : struct, IConvertible 
{ 
    var i = TryParseInt(value); 
    if (!i.HasValue) 
    { 
     return null; 
    } 

    return (T)i.Value; 
} 
+0

http://stackoverflow.com/questions/2745320/enum-tryparse-with-flags-attribute - może pomóc ? – Sunny

+0

Ostatnia odpowiedź na http://stackoverflow.com/questions/1331739/enum-type-constraints-in-c-sharp, jest bliżej tego, co chcesz. Nadal nie jest to sprytne. Używam do tego celu refleksji, możesz uczynić kod znacznie silniejszym. Struct nie jest wystarczająco powściągliwy, aby w moim przekonaniu zarabiać na generykach. –

+0

Coś, co nie działa: [c-sharp-non-boxing-conversion-of-generic-enum-to-int] (http://stackoverflow.com/questions/1189144/c-sharp-non-boxing- konwersja-generic-enum-to-int) – nawfal

Odpowiedz

76

Najprostszym sposobem znalazłem to, aby wymusić rękę kompilator dodając obsadę do object.

return (T)(object)i.Value; 
+10

Jeśli nie lubisz boksu: [c-sharp-non-boxing-conversion-of-generic-enum-to-int] (http://stackoverflow.com/questions/1189144/c-sharp-non-boxing-conversion-of-generic-enum-to-int) – nawfal

+2

Przerzucamy enum na int, a nie przeciwnie, jak w pytaniu, które łączysz. Ponadto to pytanie nie ma rozwiązania. – MatteoSp

+0

Można również po prostu przydzielić statyczną tablicę z wartościami wyliczeniowymi, a następnie po prostu przekazać indeks, aby pobrać prawidłowe wyliczenie. Oszczędza to konieczności wykonywania wszelkiego rodzaju rzutowania. Przykład (Tylko linia 11,14 i 34 są związane z tą koncepcją): https://pastebin.com/iPEzttM4 – Krythic

11

Powinieneś być w stanie wykorzystać Enum.Parse na to:

return (T)Enum.Parse(typeof(T), i.Value.ToString(), true); 

Ten artykuł mówi o parsowania stałe teksty ogólnych metod extenstion:

+0

@Guvante: Myślę, że przekonwertowałem wartość na ciąg znaków w moim przykładzie. Czy przewidujesz, że to powoduje problem? –

14

Oto bardzo szybkie rozwiązanie, które nadużywa faktu że środowisko wykonawcze tworzy wiele wystąpień statycznych klas ogólnych. Uwolnij swoje wewnętrzne demony optymalizacji!

To naprawdę świeci, gdy czytasz Odmiany w strumieniu w sposób ogólny. Połączyć z klasą zewnętrzną, która również buforuje podstawowy typ enum i BitConverter, aby uwolnić niesamowite.

void Main() 
{ 
    Console.WriteLine("Cast (reference): {0}", (TestEnum)5); 
    Console.WriteLine("EnumConverter: {0}", EnumConverter<TestEnum>.Convert(5)); 
    Console.WriteLine("Enum.ToObject: {0}", Enum.ToObject(typeof(TestEnum), 5)); 

    int iterations = 1000 * 1000 * 100; 
    Measure(iterations, "Cast (reference)",() => { var t = (TestEnum)5; }); 
    Measure(iterations, "EnumConverter",() => EnumConverter<TestEnum>.Convert(5)); 
    Measure(iterations, "Enum.ToObject",() => Enum.ToObject(typeof(TestEnum), 5)); 
} 

static class EnumConverter<TEnum> where TEnum : struct, IConvertible 
{ 
    public static readonly Func<long, TEnum> Convert = GenerateConverter(); 

    static Func<long, TEnum> GenerateConverter() 
    { 
     var parameter = Expression.Parameter(typeof(long)); 
     var dynamicMethod = Expression.Lambda<Func<long, TEnum>>(
      Expression.Convert(parameter, typeof(TEnum)), 
      parameter); 
     return dynamicMethod.Compile(); 
    } 
} 

enum TestEnum 
{ 
    Value = 5 
} 

static void Measure(int repetitions, string what, Action action) 
{ 
    action(); 

    var total = Stopwatch.StartNew(); 
    for (int i = 0; i < repetitions; i++) 
    { 
     action(); 
    } 
    Console.WriteLine("{0}: {1}", what, total.Elapsed); 
} 

wyników na podstawowej i7-3740QM z optymalizacji włączona:

Cast (reference): Value 
EnumConverter: Value 
Enum.ToObject: Value 
Cast (reference): 00:00:00.3175615 
EnumConverter: 00:00:00.4335949 
Enum.ToObject: 00:00:14.3396366 
+0

To naprawdę miłe, dzięki. Zamiast tego możesz użyć 'Expression.ConvertChecked', aby numeryczne przekroczenie zakresu typu wyliczeniowego powodowało' OverflowException'. –

0
public static class Extensions 
    { 
     public static T ToEnum<T>(this int param) 
     { 
      var info = typeof(T); 
      if (info.IsEnum) 
      { 
       T result = (T)Enum.Parse(typeof(T), param.ToString(), true); 
       return result; 
      } 

      return default(T); 
     } 
    } 
Powiązane problemy