7

次のコードがあるとします。

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

Visual Studio 2010 を .NET 2.0 アセンブリとしてコンパイルして生成された IL コードは次のとおりです。

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

私の質問は次のとおりです。

  1. MethodA で、 と の間にnopコードがないのはなぜですか? L_0006L_0007
    • L_0001toはtoとL_0006は異なるため、オペコードがないのはなぜですか?L_0007L_0009nop
  2. MethodB では、なぜL_0003必要なのですか?
4

2 に答える 2

10

C# コンパイラは、中かっこで NOP 命令を発行します。これにより、コードにブレークポイントを設定するのがはるかに簡単になります。デバッガーはコードにブレークポイントを設定することのみを許可し、中括弧は通常コードを生成しません。したがって、これは単なるデバッグ支援であり、これらの NOP はリリース ビルドでは生成されません。

BR.S 命令はコンパイラのマイナーな欠陥であり、この種の無関係な命令を取り除くためのピープホールオプティマイザがありません。一般に、コードを最適化するのは C# コンパイラの仕事ではなく、ジッターによって行われます。これにより、指示が簡単かつ簡単に削除されます。

于 2013-03-22T22:42:58.310 に答える
1

表示されるのはすべて、デバッグ モードでコンパイルしているためです。冗長なジャンプと nop は、無効化された最適化パスとデバッグ サポートです (私は信じています)。

リリース モードでコンパイルします。

于 2013-03-22T22:32:46.207 に答える