在C#中将Int强制转换为通用枚举


84

C#中将Cast转换为枚举类似,但我的枚举是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;
}


关于stackoverflow.com/questions/1331739/…的最后一个答案更接近您想要的。它仍然不是很聪明。我倾向于为此使用反射,可以使代码更强大。在我看来,Struct不够灵活,无法与泛型混为一谈。
托尼·霍普金森

Answers:


120

我发现的最简单的方法是通过将强制转换添加到来强制编译器使用object

return (T)(object)i.Value;

12
如果您不喜欢拳击,请执行以下操作:C-Sharp-non-boxing-conversion-of-generic-enum-to-int
nawfal

5
我们正在将枚举转换为int,而不是您所链接的So问题中的相反。而且,这个问题没有解决方案。
MatteoSp

您也可以只为静态数组分配枚举值,然后传入索引以检索正确的枚举。这样可以省去进行任何类型的转换。示例(仅11,14和34行与此概念相关):pastebin.com/iPEzttM4
Krythic


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);
}

在启用了优化的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

2
真的很好,谢谢。Expression.ConvertChecked不过,您可能想使用它,以便枚举类型范围的数值溢出导致OverflowException
Drew Noakes

您的里程可能会有所不同,我在try.dot.net(blazor)上运行了代码,那里的EnumConverter <T>比其他方法慢得多。首先投射到对象比直接投射慢大约6倍,但仍然比其他选择好得多。
赫尔曼



By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.