96 votes

Cast Int à Enum générique en C #

Semblable à Cast int à Enum en C # mais mon enum est un paramètre de type générique. Quelle est la meilleure façon de gérer cela?

Exemple:

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

Génère une erreur du compilateur Cannot convert type 'int' to 'T'

Le code complet est le suivant, où valeur peut contenir int ou 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;
}
 

137voto

Guvante Points 10338

La méthode la plus simple que j'ai trouvée consiste à forcer la main du compilateur en ajoutant une conversion à object .

 return (T)(object)i.Value;
 

22voto

James Johnson Points 29414

Vous devriez pouvoir utiliser Enum.Parse pour ceci:

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

Cet article traite de l’analyse d’énums génériques pour les méthodes d’extension:

18voto

Raif Atef Points 818

Voici une solution très rapide qui abuse du fait que le moteur d'exécution crée plusieurs instances de classes génériques statiques. Libérez vos démons d'optimisation internes!

Cela brille vraiment lorsque vous lisez Enums à partir d’un flux de manière générique. Combinez-le avec une classe externe qui met également en cache le type sous-jacent de l'énum et un BitConverter pour libérer le génial.

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

Résultats sur Core i7-3740QM avec optimisations activées:

 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
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X