在C#中将Int转换为Generic Enum

csa*_*uve 74 c# generics enums casting

类似于C#中的Cast int to enum,但我的枚举是Generic Type参数.处理这个问题的最佳方法是什么?

例:

private T ConvertEnum<T>(int i) where T : struct, IConvertible
{
    return (T)i;
}
Run Code Online (Sandbox Code Playgroud)

生成编译器错误 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;
}
Run Code Online (Sandbox Code Playgroud)

Guv*_*nte 108

我找到的最简单的方法是通过添加强制转换来强制编译器的手object.

return (T)(object)i.Value;
Run Code Online (Sandbox Code Playgroud)

  • 如果你不喜欢拳击:[c-sharp-non-boxing-conversion-of-generic-enum-to-int](http://stackoverflow.com/questions/1189144/c-sharp-non-boxing-转换-的泛型-枚举到INT) (11认同)
  • 我们将枚举转换为int,而不是像你链接的那个问题那样.此外,这个问题没有解决方案. (4认同)
  • 如果枚举的基础类型不是 int (即字节或长枚举,甚至 uint),这将引发异常。 (4认同)

Rai*_*tef 16

这是一个非常快速的解决方案,它滥用了运行时创建静态泛型类的多个实例这一事实.释放你的内在优化恶魔!

当您以通用方式从流中读取枚举时,这真的很棒.结合一个外部类,它也缓存枚举的底层类型和一个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);
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

  • 这真的很好,谢谢.您可能希望使用`Expression.ConvertChecked`,因此枚举类型范围的数字溢出会导致`OverflowException`. (2认同)

Jam*_*son 15

你应该可以使用Enum.Parse这个:

return (T)Enum.Parse(typeof(T), i.Value.ToString(), true);
Run Code Online (Sandbox Code Playgroud)

本文讨论解析扩展方法的通用枚举:


Emp*_*pus 7

或者,如果您不能将枚举作为泛型类型,而是作为类型获得,那么只需使用

Enum.ToObject
Run Code Online (Sandbox Code Playgroud)

https://msdn.microsoft.com/en-us/library/system.enum.toobject(v=vs.110).aspx


Ram*_*ein 6

在 .NET 核心中,现在可以像这样使用System.Runtime.CompilerServices.Unsafe代码:

return Unsafe.As<int, TEnum>(ref int32);
Run Code Online (Sandbox Code Playgroud)