2012-04-30 20 views
50

Similar a Cast int to enum in C# pero mi enum es un parámetro de tipo genérico. ¿Cuál es la mejor forma de manejarlo? Cast Int para Enumerar genérico en C#

Ejemplo:

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

genera error compilador Cannot convert type 'int' to 'T'

código completa es como sigue, donde el valor puede contener el int, o nulo.

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 - podrían ayudar ? – Sunny

+0

Última respuesta en http://stackoverflow.com/questions/1331739/enum-type-constraints-inc-c-sharp, está más cerca de lo que desea. Todavía no es inteligente. Tiendo a usar el reflejo para esto, puedes hacer que el código sea mucho más fuerte. Struct no es lo suficientemente retrictivo como para molestar a los genéricos en mi opinión. –

+0

Algo que no encajona: [c-sharp-no-boxing-conversion-of-generic-enum-to-int] (http://stackoverflow.com/questions/1189144/c-sharp-non-boxing- conversion-of-generic-enum-to-int) – nawfal

Respuesta

76

La forma más sencilla que he encontrado es para forzar la mano del compilador mediante la adición de un yeso para object.

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

Si no te gusta el boxeo: [c-sharp-no-boxing-conversion-of-generic-enum-to-int] (http://stackoverflow.com/questions/1189144/c-sharp-non-boxing-conversion-of-generic-enum-to-int) – nawfal

+2

Estamos lanzando enum a int, no al contrario como en la pregunta que enlazas. Además, esa pregunta no tiene solución. – MatteoSp

+0

También podría asignar una matriz estática con los valores enum, y luego simplemente pasar el índice para recuperar la enumeración correcta. Esto ahorra tener que hacer cualquier tipo de casting. Ejemplo (Solo las líneas 11, 14 y 34 son relevantes para este concepto): https://pastebin.com/iPEzttM4 – Krythic

11

Usted debe ser capaz de utilizar Enum.Parse para esto:

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

Este artículo habla de analizar las enumeraciones genéricas de métodos extenstion:

+0

@Guvante: Creo que convertí el valor a una cadena en mi ejemplo. ¿Prevé esto causando un problema? –

14

He aquí una solución muy rápida que abusa del hecho que el tiempo de ejecución crea múltiples instancias de clases genéricas estáticas. ¡Desata tus demonios de optimización interna!

Esto realmente brilla cuando estás leyendo Enums de una secuencia de una manera genérica. Combínelo con una clase externa que también almacena en caché el tipo subyacente de la enumeración y un BitConverter para liberar lo increíble.

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

Resultados de Core i7-3740QM con optimizaciones habilitadas:

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

Esto es realmente agradable, gracias. Sin embargo, es posible que desee utilizar 'Expression.ConvertChecked' en su lugar, de modo que el desbordamiento numérico del rango del tipo enum resulte en una '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); 
     } 
    }