คำตอบสั้น ๆ :
ไม่มีคำสั่ง "เปรียบเทียบไม่เท่ากับ" ใน IL ดังนั้น!=
ผู้ประกอบการC # จึงไม่มีการติดต่อที่แน่นอนและไม่สามารถแปลได้อย่างแท้จริง
มี แต่ "เปรียบเทียบเท่ากับ" การเรียนการสอน ( ceq
มีการติดต่อโดยตรงกับ==
ผู้ดำเนินการ) ดังนั้นในกรณีทั่วไปได้รับการแปลเช่นอีกเล็กน้อยเทียบเท่าx != y
(x == y) == false
นอกจากนี้ยังมีคำสั่ง "เปรียบเทียบมากกว่ามากกว่า" ใน IL ( cgt
) ซึ่งอนุญาตให้คอมไพเลอร์ใช้ทางลัดบางอย่าง (เช่นสร้างรหัส IL ที่สั้นกว่า) หนึ่งในนั้นคือการเปรียบเทียบความไม่เท่าเทียมกันของวัตถุกับ null 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;
}
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
}
คอมไพเลอร์สามารถใช้ประโยชน์จากความจริงที่ว่าเลขจำนวนเต็มที่ลงนามนั้นถูกเก็บไว้ในส่วนเสริมของสอง (ซึ่งหากรูปแบบบิตที่ได้รับการตีความเป็นจำนวนเต็มแบบไม่ได้ลงนาม - นั่นคือสิ่งที่.un
หมายถึง - 0 มีค่าน้อยที่สุด) ดังนั้นมันแปลx == 0
ว่าunchecked((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 Standard (ฉบับที่ 1 จากตุลาคม 2003) (หน้า 491 เป็นเชิงอรรถของตารางที่ 6-4, "การเปรียบเทียบไบนารีหรือการดำเนินการสาขา"):
" cgt.un
ได้รับอนุญาตและตรวจสอบได้ใน ObjectRefs (O) สิ่งนี้มักใช้เมื่อเปรียบเทียบ ObjectRef กับ null (ไม่มีคำสั่ง" เปรียบเทียบไม่เท่ากัน "ซึ่งจะเป็นทางออกที่ชัดเจนมากขึ้น)
int
's ช่วงมีการแสดงเหมือนกันในขณะที่พวกเขาทำในint
uint
นั่นเป็นข้อกำหนดที่อ่อนแอกว่าทั้งสองข้อ