Приведение Int к общему перечислению в C#
похоже на приведение int к enum в C#, но мое перечисление является параметром универсального типа. Что такое лучшие способ справиться с этим?
пример:
private T ConvertEnum<T>(int i) where T : struct, IConvertible
{
return (T)i;
}
выдает ошибку компилятора Cannot convert type 'int' to 'T'
полный код выглядит следующим образом, где значение может содержать int или 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;
}
5 ответов:
самый простой способ, который я нашел, - это заставить руку компилятора добавить приведение к
object
.return (T)(object)i.Value;
вот очень быстрое решение, которое злоупотребляет тем фактом, что среда выполнения создает несколько экземпляров статических универсальных классов. Дайте волю своим внутренним демонам оптимизации!
Это действительно сияет, когда вы читаете перечислений из потока в общем виде. Объедините с внешним классом, который также кэширует базовый тип enum и BitConverter, чтобы развязать awesome.
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); }
результаты на Core i7-3740QM с включенной оптимизацией:
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
вы должны быть в состоянии использовать
Enum.Parse
для этого:return (T)Enum.Parse(typeof(T), i.Value.ToString(), true);
в этой статье говорится о разборе общих перечислений для методов расширения:
альтернативно, если вы можете получить перечисление не как общий тип, А как тип, то просто используйте
Enum.ToObject
https://msdn.microsoft.com/en-us/library/system.enum.toobject(v=vs. 110).aspx