Similar a Cast int to enum en C # pero mi enum es un parámetro de tipo genérico. ¿Cuál es la mejor manera de manejar esto?
Ejemplo:
private T ConvertEnum<T>(int i) where T : struct, IConvertible
{
return (T)i;
}
Genera error del compilador Cannot convert type 'int' to 'T'
El código completo es el siguiente, donde el valor puede contener int o 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;
}
Respuestas:
La forma más sencilla que he encontrado es forzar la mano del compilador agregando un molde a
object
.return (T)(object)i.Value;
fuente
Debería poder usar
Enum.Parse
para esto:return (T)Enum.Parse(typeof(T), i.Value.ToString(), true);
Este artículo habla sobre el análisis de enumeraciones genéricas para métodos de extensión:
fuente
Aquí hay una solución muy rápida que abusa del hecho de que el tiempo de ejecución crea múltiples instancias de clases genéricas estáticas. ¡Desata tus demonios internos de optimización!
Esto realmente brilla cuando estás leyendo Enums de una transmisión de forma genérica. Combine con una clase externa que también almacena en caché el tipo subyacente de la enumeración y un BitConverter para dar rienda suelta a lo impresionante.
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 en 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
fuente
Expression.ConvertChecked
embargo, es posible que desee en lugar, de modo que el desbordamiento numérico del rango del tipo de enumeración dé como resultado unOverflowException
.Alternativamente, si puede obtener una enumeración no como un tipo genérico, sino como Type, simplemente use
https://msdn.microsoft.com/en-us/library/system.enum.toobject(v=vs.110).aspx
fuente
En .NET core ahora es posible usar System.Runtime.CompilerServices.Unsafe código como este:
return Unsafe.As<int, TEnum>(ref int32);
fuente
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); } }
fuente