【发布时间】:2018-09-16 00:28:35
【问题描述】:
我的这段代码会发出一些 IL 指令,这些指令在 null 对象上调用 string.IndexOf:
MethodBuilder methodBuilder = typeBuilder.DefineMethod(
"Foo",
MethodAttributes.Public,
typeof(void), Array.Empty<Type>());
var methodInfo = typeof(string).GetMethod("IndexOf", new[] {typeof(char)});
ILGenerator ilGenerator = methodBuilder.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldnull);
ilGenerator.Emit(OpCodes.Ldc_I4_S, 120);
ilGenerator.Emit(OpCodes.Call, methodInfo);
ilGenerator.Emit(OpCodes.Ret);
这是生成的IL 代码:
.method public instance int32 Foo() cil managed
{
// Code size 12 (0xc)
.maxstack 2
IL_0000: ldnull
IL_0001: ldc.i4.s 120
IL_0003: nop
IL_0004: nop
IL_0005: nop
IL_0006: call instance int32 [mscorlib]System.String::IndexOf(char)
IL_000b: ret
} // end of method MyDynamicType::Foo
如您所见,call 指令之前有三个 nop 指令。
首先我想到的是 Debug/Release 构建,但这不是编译器生成的代码,我正在发出原始 IL 代码并希望看到它的原样。
所以我的问题是为什么我没有发出任何 nop 指令?
【问题讨论】:
-
很高兴有 3 个额外的点来断点你的代码:P 但它很奇怪
-
@Arend 我不这么认为,因为那里没有使用 emit,编译器添加了 nop 指令以启用调试。您只能在指令上设置断点,但想象在方法的开头设置断点,您可以在第一个大括号上设置断点,因为大括号不包含在生成的 IL 中,编译器会发出 nop 指令,允许您在那里设置断点。
-
除了出色的答案之外,我想说不要太担心 nops 偶尔会出现。无论如何,它们都会被 JIT 忽略。
标签: c# cil reflection.emit ilgenerator