147

私は偶然にも、C# コンパイラがこのメソッドを有効にしていることを発見しました。

static bool IsNotNull(object obj)
{
    return obj != null;
}

…このCILに:

.method private hidebysig static bool IsNotNull(object obj) cil managed
{
    ldarg.0   // obj
    ldnull
    cgt.un
    ret
}

…または、逆コンパイルされた C# コードを見たい場合:

static bool IsNotNull(object obj)
{
    return obj > null;   // (note: this is not a valid C# expression)
}

!=" " と翻訳されるのは>なぜですか?

4

1 に答える 1

201

簡潔な答え:

IL には「compare-not-equal」命令がないため、C#!=演算子には正確な対応がなく、文字通りに変換できません。

ただし、「compare-equal」命令 ( 、演算子ceqへの直接対応) があるため、一般的なケースでは、少し長い同等の のように変換されます。==x != y(x == y) == false

IL ( ) には「より大なり比較」命令もありcgtこれによりコンパイラは特定のショートカットを実行できます (つまり、より短い IL コードを生成できます) obj != nullobj > null"。

もう少し詳しく見てみましょう。

ILに「compare-not-equal」命令がない場合、次のメソッドはコンパイラによってどのように変換されますか?

static bool IsNotEqual(int x, int y)
{
    return x != y;
}

すでに上で述べたように、コンパイラは を にx != y変換し(x == y) == falseます:

.method private hidebysig static bool IsNotEqual(int32 x, int32 y) cil managed 
{
    ldarg.0   // x
    ldarg.1   // y
    ceq
    ldc.i4.0  // false
    ceq       // (note: two comparisons in total)
    ret
}

コンパイラは、このかなり長いパターンを常に生成するとは限りません。yを定数 0に置き換えるとどうなるか見てみましょう。

static bool IsNotZero(int x)
{
    return x != 0;
}

生成される IL は、一般的な場合よりも若干短くなります。

.method private hidebysig static bool IsNotZero(int32 x) cil managed 
{
    ldarg.0    // x
    ldc.i4.0   // 0
    cgt.un     // (note: just one comparison)
    ret
}

コンパイラは、符号付き整数が2 の補数で格納されるという事実を利用できます(ここで、結果のビット パターンが符号なし整数として解釈される場合、つまり、0.unが可能な限り最小の値を持ちます)。.x == 0unchecked((uint)x) > 0

コンパイラーは、以下に対する不等式チェックに対してまったく同じことができることがわかりましたnull

static bool IsNotNull(object obj)
{
    return obj != null;
}

コンパイラは、 とほぼ同じ IL を生成しIsNotZeroます。

.method private hidebysig static bool IsNotNull(object obj) cil managed 
{
    ldarg.0
    ldnull   // (note: this is the only difference)
    cgt.un
    ret
}

どうやら、コンパイラは、null参照のビット パターンが任意のオブジェクト参照で可能な最小のビット パターンであると想定することが許可されています。

このショートカットは、 Common Language Infrastructure Annotated Standard (2003 年 10 月の第 1 版) (491 ページ、表 6-4「バイナリ比較または分岐操作」の脚注)で明示的に言及されています。

" cgt.unObjectRefs (O) で許可され、検証可能です。これは、ObjectRef を null と比較するときに一般的に使用されます ("compare-not-equal" 命令はありません。それ以外の場合は、より明白な解決策になります)。

于 2015-02-28T12:43:57.077 に答える