Коротка відповідь:
В IL немає інструкції "порівняти не рівне", тому !=оператор C # не має точної відповідності і не може бути перекладений буквально.
Однак існує інструкція "порівняти-рівну" ( ceqпряма відповідність ==оператору), тому в загальному випадку x != yперекладається як її трохи довший еквівалент (x == y) == false.
Існує також інструкція "порівняти-перевищувати", ніж в IL ( cgt), яка дозволяє компілятору приймати певні ярлики (тобто генерувати коротший код IL), одна з яких полягає в тому, що порівняння нерівності об'єктів проти нуля, obj != nullпереводиться так, ніби вони " obj > null".
Розглянемо детальніше.
Якщо в IL немає інструкції "порівняти-не-рівну", то як компілятор переведе наступний метод?
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;
}
Отриманий ІЛ дещо коротший, ніж у загальному випадку:
.method private hidebysig static bool IsNotZero(int32 x) cil managed
{
ldarg.0 // x
ldc.i4.0 // 0
cgt.un // (note: just one comparison)
ret
}
Компілятор може скористатися тим, що підписані цілі числа зберігаються в доповненнях двох (де, якщо отримані бітові шаблони інтерпретуються як цілі числа без підпису - це те, що .unозначає - 0 має найменше можливе значення), тому він перекладається x == 0так, ніби unchecked((uint)x) > 0.
Виявляється, компілятор може зробити те саме для перевірки нерівності щодо null:
static bool IsNotNull(object obj)
{
return obj != null;
}
Компілятор видає майже той самий ІЛ, що і для IsNotZero:
.method private hidebysig static bool IsNotNull(object obj) cil managed
{
ldarg.0
ldnull // (note: this is the only difference)
cgt.un
ret
}
Мабуть, компілятору дозволено припустити, що бітова модель nullпосилання є найменшим шаблоном бітів, можливим для будь-якого посилання на об'єкт.
Цей ярлик явно згадується в Анотованому стандарті загальної мовної інфраструктури (1-е видання від жовтня 2003 р.) (На стор. 491, як виноска до таблиці 6-4, "Бінарні порівняння або операції з філіями"):
" cgt.unдозволено і перевірено в ObjectRefs (O). Це зазвичай використовується при порівнянні ObjectRef з null (немає інструкції" порівняти-не-рівно ", яка в іншому випадку була б більш очевидним рішенням."
intМає значення лише те, що підписані цілі числа зберігаються таким чином, що негативні значення в діапазоні 's мають таке ж представлення,intяк і вuint. Це набагато слабша вимога, ніж доповнення двох.