假设我有以下的code:
公共类的Class1
{
私人的Class2 OBJ;
公共无效方法a()
{
VAR类2 =新的Class2();
class2.PropertyI = 2;
OBJ =方法b(等级2);
}
公众的Class2方法b(等级2等级2)
{
返回Class2的;
}
}
公共类的Class2
{
公众诠释PropertyI {获得;组; }
}
生成的IL $ C $从使用Visual Studio 2010作为.NET 2.0的程序集编译C如下:
。方法公开hidebysig实例无效治法()CIL管理
{
.maxstack 3
.locals的init(
[0]类ClassLibrary1.Class2类2)
L_0000:NOP
L_0001:newobj实例无效ClassLibrary1.Class2 ::构造函数()。
L_0006:stloc.0
L_0007:ldloc.0
L_0008:ldc.i4.2
L_0009:callvirt实例无效ClassLibrary1.Class2 :: set_PropertyI(INT32)
L_000e:NOP
L_000f:ldarg.0
L_0010:ldarg.0
L_0011:ldloc.0
L_0012:调用实例类ClassLibrary1.Class2 ClassLibrary1.Class1 ::方法b(类ClassLibrary1.Class2)
L_0017:stfld类ClassLibrary1.Class2 ClassLibrary1.Class1 :: OBJ
L_001c:RET
}
。方法公开hidebysig实例类ClassLibrary1.Class2方法b(类ClassLibrary1.Class2等级2)CIL管理
{
.maxstack 1
.locals的init(
[0]类ClassLibrary1.Class2 CS $ 1 $ 0000)
L_0000:NOP
L_0001:ldarg.1
L_0002:stloc.0
L_0003:br.s L_0005
L_0005:ldloc.0
L_0006:RET
}
我的问题有以下几种:
在治法,为什么会出现不是 NOP
code之间 L_0006
和 L_0007
?
由于 L_0001
到 L_0006
从 L_0007
不同的以 L_0009
,为什么没有 NOP
运算code?
在方法b,为什么 L_0003
有必要吗?
解决方案 C#编译器发出的一个大括号NOP指令。这使得它的很多的更容易设置在code断点。调试器只允许设置在code和一个大括号通常不会产生任何code断点。所以,这只是一个简单的调试援助,这些NOP指令将不会在发布版本获取生成。
该BR.S指令是在编译器中一个小小的瑕疵,它没有一个窥孔优化获得摆脱这类外来指令。一般情况下,它不是C#的编译器的工作,以优化code,这是由the抖动。这很容易和方便地取出指令。
Suppose I have the following code:
public class Class1
{
private Class2 obj;
public void MethodA()
{
var class2 = new Class2();
class2.PropertyI = 2;
obj = MethodB(class2);
}
public Class2 MethodB(Class2 class2)
{
return class2;
}
}
public class Class2
{
public int PropertyI { get; set; }
}
The generated IL code from compiling with Visual Studio 2010 as a .NET 2.0 assembly is the following:
.method public hidebysig instance void MethodA() cil managed
{
.maxstack 3
.locals init (
[0] class ClassLibrary1.Class2 class2)
L_0000: nop
L_0001: newobj instance void ClassLibrary1.Class2::.ctor()
L_0006: stloc.0
L_0007: ldloc.0
L_0008: ldc.i4.2
L_0009: callvirt instance void ClassLibrary1.Class2::set_PropertyI(int32)
L_000e: nop
L_000f: ldarg.0
L_0010: ldarg.0
L_0011: ldloc.0
L_0012: call instance class ClassLibrary1.Class2 ClassLibrary1.Class1::MethodB(class ClassLibrary1.Class2)
L_0017: stfld class ClassLibrary1.Class2 ClassLibrary1.Class1::obj
L_001c: ret
}
.method public hidebysig instance class ClassLibrary1.Class2 MethodB(class ClassLibrary1.Class2 class2) cil managed
{
.maxstack 1
.locals init (
[0] class ClassLibrary1.Class2 CS$1$0000)
L_0000: nop
L_0001: ldarg.1
L_0002: stloc.0
L_0003: br.s L_0005
L_0005: ldloc.0
L_0006: ret
}
My questions are the following:
In MethodA, why is there not anop
code between L_0006
and L_0007
?
Since L_0001
to L_0006
are distinct from L_0007
to L_0009
, why is there no nop
opcode?
In MethodB, why is L_0003
necessary?
解决方案
The C# compiler emits a NOP instruction at a curly brace. Which makes it a lot easier to set breakpoints in your code. The debugger only permits setting a breakpoint on code and a curly brace doesn't normally produce any code. So this is just a simple debugging aid, these NOPs won't get generated in the release build.
The BR.S instruction is a minor flaw in the compiler, it doesn't have a peephole optimizer to get rid of these kind of extraneous instructions. In general, it is not the job of the C# compiler to optimize code, that's done by the jitter. Which will readily and easily remove the instruction.