Cast Int to Generic Enum in C#


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 un error del compilador Cannot convert type 'int' to 'T'

El código completo es el siguiente, donde el valor puede contener el 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;
}
Author: Community, 2012-04-30

5 answers

La forma más sencilla que he encontrado es forzar la mano del compilador añadiendo un cast a object.

return (T)(object)i.Value;
 86
Author: Guvante,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-30 16:30:18

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 Enumeraciones de una transmisión de una manera genérica. Combínalo con una clase externa que también almacena en caché el tipo subyacente de la enumeración y un BitConverter para liberar 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
 15
Author: Raif Atef,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-10 00:02:41

Deberías 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 enums genéricos para métodos de extensión:

 14
Author: James Johnson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-30 16:39:45

Alternativamente, si puede obtener una enumeración no como un tipo genérico, sino como Tipo, simplemente use

Enum.ToObject

Https://msdn.microsoft.com/en-us/library/system.enum.toobject (v=vs.110). aspx

 1
Author: Empus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-21 08:22:13
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);
        }
    }
 0
Author: Vladimir Kurguzov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-07 11:19:55