所以我在C#中编写了以下代码。
class Test
{
int a;
System.IO.StreamReader reader;
public Test()
{
a = 5;
reader = new System.IO.StreamReader(String.Empty);
}
}
IL中类的构造函数看起来像这样
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 33 (0x21)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: nop
IL_0008: ldarg.0
IL_0009: ldc.i4.5
IL_000a: stfld int32 Test2.Test::a
IL_000f: ldarg.0
IL_0010: ldsfld string [mscorlib]System.String::Empty
IL_0015: newobj instance void [mscorlib]System.IO.StreamReader::.ctor(string)
IL_001a: stfld class [mscorlib]System.IO.StreamReader Test2.Test::reader
IL_001f: nop
IL_0020: ret
} // end of method Test::.ctor
有3个nop
命令。 (据我所知,这表示无操作)。这些命令的需要是什么。我的意思是,如果根本没有命令而不是nop
答案 0 :(得分:18)
C#编译器在为程序写入.pdb文件时使用它们。其中包含调试信息,其中包含代码的文件+行号信息。调试器使用它来查找需要注入INT 3
指令的机器代码,以便在设置断点时让程序停止执行。抖动为MSIL中的每个Opcodes.Nop发出NOP机器代码指令。
在public Test()
上设置断点时使用第一个nop。请注意,在基础构造函数调用之后注入,以便此变量在Auto / Locals / Watch调试窗口中变为有效。
在第一个{花括号上设置断点时使用第二个nop。该行根本不生成任何代码,因此非常需要伪造的MSIL指令。
第三个nop的相同故事,为最后一个}大括号生成。当您在该断点上设置断点时,您可以检查方法返回值(如果有)。在Debug + Windows + Registers窗口中间接可见。在VS2013中得到改进。
因此,这只是帮助调试程序,它们使断点可以预测。在构建程序的Release配置时,会生成 not 的NOP。 C#项目具有Debug和Release配置的一个重要原因。你仍然可以调试一个Release版本,但这是一个相当混乱的体验,让你怀疑你的理智:)
答案 1 :(得分:3)
它们用于在调试模式下构建时支持断点,并且对程序集的执行没有任何影响。