Similaire à Cast int pour 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 de compilation Cannot convert type 'int' to 'T'
Le code complet est le suivant, où la valeur peut contenir l'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;
}
La manière la plus simple que j'ai trouvée est de forcer la main du compilateur en ajoutant un transtypage à object
.
return (T)(object)i.Value;
Voici une solution très rapide qui abuse du fait que le runtime crée plusieurs instances de classes génériques statiques. Libérez vos démons d'optimisation intérieure!
Cela brille vraiment lorsque vous lisez Enums à partir d'un flux de manière générique. Combinez avec une classe externe qui met également en cache le type sous-jacent de l'énumération et un BitConverter pour libérer l'impressionnant.
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
Vous devriez pouvoir utiliser Enum.Parse
pour ça:
return (T)Enum.Parse(typeof(T), i.Value.ToString(), true);
Cet article traite de l'analyse des énumérations génériques pour les méthodes d'extension:
Alternativement, si vous pouvez obtenir une énumération non pas en tant que type générique, mais en tant que type, utilisez simplement
Enum.ToObject
https://msdn.Microsoft.com/en-us/library/system.enum.toobject (v = vs.110) .aspx
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);
}
}