C#非拳击通用枚举转换为int?拳击、转换为、int

2023-09-02 10:42:37 作者:捏碎你的虚伪

给出一个泛型参数TEnum总是将枚举类型,有没有办法从TEnum投不装箱/拆箱为int?

Given a generic parameter TEnum which always will be an enum type, is there any way to cast from TEnum to int without boxing/unboxing?

请参阅本例中code。这将盒/拆箱不必要的价值。

See this example code. This will box/unbox the value unnecessarily.

private int Foo<TEnum>(TEnum value)
    where TEnum : struct  // C# does not allow enum constraint
{
    return (int) (ValueType) value;
}

以上C#是编译为以下的IL(注装箱和拆箱操作codeS)释放模式:

The above C# is release-mode compiled to the following IL (note boxing and unboxing opcodes):

.method public hidebysig instance int32  Foo<valuetype 
    .ctor ([mscorlib]System.ValueType) TEnum>(!!TEnum 'value') cil managed
{
  .maxstack  8
  IL_0000:  ldarg.1
  IL_0001:  box        !!TEnum
  IL_0006:  unbox.any  [mscorlib]System.Int32
  IL_000b:  ret
}

枚举转化已被广泛视为对SO,但我无法找到一个讨论处理这一特殊情况。

Enum conversion has been treated extensively on SO, but I could not find a discussion addressing this specific case.

推荐答案

我不知道这是可能在C#中不使用Reflection.Emit的。如果您使用Reflection.Emit的,你可以加载枚举压入堆栈的值,然后把它好像它是一个int。

I'm not sure that this is possible in C# without using Reflection.Emit. If you use Reflection.Emit, you could load the value of the enum onto the stack and then treat it as though it's an int.

您必须虽然写了不少的code,所以你要检查你是否会真正在做这个的任何性能。

You have to write quite a lot of code though, so you'd want to check whether you'll really gain any performance in doing this.

相信同等IL是:

.method public hidebysig instance int32  Foo<valuetype 
    .ctor ([mscorlib]System.ValueType) TEnum>(!!TEnum 'value') cil managed
{
  .maxstack  8
  IL_0000:  ldarg.1
  IL_000b:  ret
}

请注意,如果你的枚举源于此会失败(64位整数。)

Note that this would fail if your enum derived from long (a 64 bit integer.)

修改

这种方法的另一种思考。 Reflection.Emit的可以创建上面的方法,但你必须结合它的唯一方法是通过虚拟调用(即它实现了编译时已知的接口/抽象的,你可以调用)或间接调用(即通过委托调用)。我想,这两种情况会比拳的开销/拆箱反正。

Another thought on this approach. Reflection.Emit can create the method above, but the only way you'd have of binding to it would be via a virtual call (i.e. it implements a compile-time known interface/abstract that you could call) or an indirect call (i.e. via a delegate invocation). I imagine that both of these scenarios would be slower than the overhead of boxing/unboxing anyway.

另外,不要忘记,JIT不哑,可能照顾这个要求。 (修改的看到原来的问题埃里克利珀的评论 - 他说,抖动目前不执行此优化的。)

Also, don't forget that the JIT is not dumb and may take care of this for you. (EDIT see Eric Lippert's comment on the original question -- he says the jitter does not currently perform this optimisation.)

与所有的性能相关的问题:测量,测量,测量

As with all performance related issues: measure, measure, measure!