Подобно Cast int to enum в C #, но мое перечисление является параметром Generic Type. Как лучше всего с этим справиться?
Пример:
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;
}
Ответы:
Самый простой способ, который я нашел, - заставить компилятор работать, добавив приведение к
object
.return (T)(object)i.Value;
источник
Вы должны уметь использовать
Enum.Parse
для этого:return (T)Enum.Parse(typeof(T), i.Value.ToString(), true);
В этой статье рассказывается о разборе общих перечислений для методов расширения:
источник
Вот очень быстрое решение, которое злоупотребляет тем фактом, что среда выполнения создает несколько экземпляров статических универсальных классов. Дайте волю своим демонам внутренней оптимизации!
Это действительно замечательно, когда вы читаете Enums из потока обычным образом. Объедините с внешним классом, который также кэширует базовый тип перечисления, и BitConverter, чтобы раскрыть потрясающие возможности.
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
источник
Expression.ConvertChecked
вместо этого, чтобы числовое переполнение диапазона типа перечисления приводило к расширениюOverflowException
.В качестве альтернативы, если вы можете получить перечисление не как общий тип, а как тип, просто используйте
https://msdn.microsoft.com/en-us/library/system.enum.toobject(v=vs.110).aspx
источник
В ядре .NET теперь можно использовать код System.Runtime.CompilerServices.Unsafe следующим образом:
return Unsafe.As<int, TEnum>(ref int32);
источник
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); } }
источник