与Cast int to enum in C#类似,但我的枚举是Generic Type参数。什么是最佳方式来处理这个问题?
示例:
private T ConvertEnum<T>(int i) where T : struct, IConvertible
{
return (T)i;
}
生成编译器错误Cannot convert type 'int' to 'T'
完整代码如下,其中value可以包含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;
}
答案 0 :(得分:100)
我找到的最简单方法是通过向object
添加强制转换来强制编译器。
return (T)(object)i.Value;
答案 1 :(得分:15)
您应该可以使用Enum.Parse
:
return (T)Enum.Parse(typeof(T), i.Value.ToString(), true);
本文讨论解析扩展方法的通用枚举:
答案 2 :(得分:15)
这是一个非常快速的解决方案,它滥用了运行时创建静态泛型类的多个实例这一事实。释放你的内在优化恶魔!
当您以通用方式从流中读取枚举时,这真的很棒。 结合一个外部类,它也缓存枚举的底层类型和一个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
答案 3 :(得分:4)
在.NET核心中,现在可以使用System.Runtime.CompilerServices.Unsafe这样的代码:
return Unsafe.As<int, TEnum>(ref int32);
答案 4 :(得分:1)
或者,如果您可以获得的枚举不是通用类型,而是类型,则只需使用
Enum.ToObject
https://msdn.microsoft.com/en-us/library/system.enum.toobject(v=vs.110).aspx
答案 5 :(得分:0)
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);
}
}
答案 6 :(得分:0)
我不喜欢Object
演员表,所以我建议:
TEnum enumValue = (TEnum)Enum.ToObject(typeof(TEnum), intValue);
我不喜欢:
(T)(object)value;
因为:
value
可以是任何东西,甚至可以是复杂的类型int
),我们将int装箱并拆箱。 答案 7 :(得分:0)
((T[])Enum.GetValues(typeof(T))) 可用于构建从int到Enum类型的字典/查找表 总的来说,我更喜欢 Ramon 使用“Unsafe.As”的演员表,因为枚举是整数的薄饰面,似乎不值得假装建造城堡(并不是说薄是件坏事)。请注意 C# 7.3 中的 Enum 类型约束。 (基本的事情是我们可以在通用枚举约束下转换 T 的数组)
(如果我有代表,这将是一个评论)
public static TEnum IntToEnum<TEnum>(int i)
where TEnum : Enum
{
Array array = Enum.GetValues(typeof(TEnum));
int[] intValues = (int[])array;
TEnum[] enumValues = (TEnum[])array;
var b = intValues.Zip(enumValues);
//Consider saving the dictionary to avoid recreating each time
var c = b.ToDictionary<(int n, TEnum e), int, TEnum>(p => p.n, p => p.e);
return c[i];//KeyNotFoundException possible here
}
应该在@trinalbadger587 指出的可怕错误之后工作 (谢谢.. https://dotnetfiddle.net/1oYWjD )
答案 8 :(得分:0)
这是一个新的答案,因为它是一个不同的看法。古老的问题,但我昨天正在这样做......所以
类似于@Ramon-de-Klein 并使用来自@trinalbadger587 的 dotnet-fiddle 示例
相当简洁和不透明,但有时没关系。 请注意,如果枚举存储在字节或 16 位 ushort 中,则需要正确的基础值类型
//Int to Enum using the hot span newness - but without unsafe{}
Span<int> XS = stackalloc int[] { 100 };
Console.WriteLine(MemoryMarshal.Cast<int, Bla>(XS)[0]);
//Int to Enum using good old arrays
Console.WriteLine(((Bla[])(Array)(new int[] { 100 }))[0]);
//Enum to Int
Console.WriteLine(((int[])(Array)(new Bla[] { Bla.B }))[0]);
enum Bla
{
A = 0,
B = 100
}