通用枚举到int的C#非装箱转换? [英] C# non-boxing conversion of generic enum to int?

查看:31
本文介绍了通用枚举到int的C#非装箱转换?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定一个通用参数 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?

请参阅此示例代码.这将不必要地装箱/拆箱该值.

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(注意装箱和拆箱操作码):

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.

不过,您必须编写大量代码,因此您需要检查这样做是否真的可以获得任何性能.

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 是:

I believe the equivalent IL would be:

.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
}

请注意,如果您的枚举派生自 long(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 并不笨,它可能会为您处理这个问题.(编辑请参阅 Eric Lippert 对原始问题的评论——他说抖动目前不执行此优化.)

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!

这篇关于通用枚举到int的C#非装箱转换?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆