在C#中将Int转换为Generic Enum

Cast Int to Generic Enum in C#

类似于将int强制转换为c中的枚举,但我的枚举是一个泛型类型参数。最好的方法是什么?

例子:

1
2
3
4
private T ConvertEnum<T>(int i) where T : struct, IConvertible
{
    return (T)i;
}

生成编译器错误Cannot convert type 'int' to 'T'

完整代码如下,其中值可以包含int或null。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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添加一个强制转换来强制编译程序。

1
return (T)(object)i.Value;


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

当你以一种通用的方式从一个流中读取枚举时,这真的很亮。结合一个外部类,该类还缓存枚举的基础类型和一个bitconverter,以释放出令人敬畏的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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);
}

启用优化的核心i7-3740qm上的结果:

1
2
3
4
5
6
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进行以下操作:

1
return (T)Enum.Parse(typeof(T), i.Value.ToString(), true);

本文讨论如何解析扩展方法的泛型枚举:

  • 使用扩展方法进行泛型枚举分析


或者,如果可以将枚举不作为泛型类型而是作为类型获取,则只需使用

1
Enum.ToObject

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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);
        }
    }