同一方法体的不同IL代码



假设我有以下类:

public class SomeClass
{
    public int GetValue()
    {
        return 1;
    }
}

检查为此方法生成的IL代码:

byte[] methodBody = typeof(SomeClass).GetMethod("GetValue").GetMethodBody().GetILAsByteArray();

我们得到methodBody =

[0, 23, 10, 43, 0, 6, 42] -- 7 bytes

使用反射创建我自己的方法。发出:

MethodBuilder methodBuilder = typeBuilder.DefineMethod("GetValue", MethodAttributes.Public, typeof(int), Type.EmptyTypes);
ILGenerator il = methodBuilder.GetILGenerator();
il.Emit(OpCodes.Ldc_I4, 1);
il.Emit(OpCodes.Ret);
//....
byte[] dynamicMethodBody = dynamicType.GetMethod("GetValue").GetMethodBody().GetILAsByteArray();

得到dynamicMethodBody =

[32, 1, 0, 0, 0, 42] -- 6 bytes

为什么两个方法体不同?它们不是完全一样吗?

此外,我猜dynamicMethodBody中的前两个字节321与将常量1加载到评估堆栈有关,但为什么methodBody中不存在这两个字节?

如果您在调试模式下编译SomeClass,编译器将插入许多额外的东西,只是为了使调试体验更好。事实证明,在简单的情况下,优化的IL可以更容易阅读。

对于编译器生成的体,我相信它正在生成noop (0), Ldc_I4_1(23),然后是本地和分支指令中的一些存储(我不确定我是否遵循),然后是Ret(42)。这是基于debug中的反编译代码:

IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: stloc.0
IL_0003: br.s IL_0005
IL_0005: ldloc.0
IL_0006: ret

你可以在反编译的发布代码中看到,指令要简单得多:

IL_0000: ldc.i4.1
IL_0001: ret

我相信dynamicMethodBody是Ldc_I4(32)的1字节,整数1(1 0 0 0)的4字节,然后是Ret(42)。

所以你的代码比编译器在发布模式下生成的代码要冗长一些,因为有一个内置的32位整数1的操作码。

相关内容

  • 没有找到相关文章

最新更新