โอเวอร์โหลดเท่ากับโอเปอเรเตอร์
ในความเป็นจริงมีความแตกต่างในความหมายระหว่างการเปรียบเทียบทั้งสองเมื่อคุณเปรียบเทียบnull
กับประเภทที่มี==
ผู้ให้บริการมากเกินไป foo is null
จะใช้การเปรียบเทียบการอ้างอิงโดยตรงเพื่อกำหนดผลลัพธ์ในขณะที่foo == null
แน่นอนว่าจะเรียกใช้ตัวดำเนินการโอเวอร์โหลด==
หากมีอยู่
ในตัวอย่างนี้ฉันได้แนะนำ "บั๊ก" ในตัว==
ดำเนินการโอเวอร์โหลดทำให้เกิดข้อผิดพลาดเสมอถ้าอาร์กิวเมนต์ที่สองคือnull
:
void Main()
{
Foo foo = null;
if (foo is null) Console.WriteLine("foo is null"); // This condition is met
if (foo == null) Console.WriteLine("foo == null"); // This will throw an exception
}
public class Foo
{
public static bool operator ==(Foo foo1, Foo foo2)
{
if (object.Equals(foo2, null)) throw new Exception("oops");
return object.Equals(foo1, foo2);
}
// ...
}
รหัส IL สำหรับfoo is null
ใช้ceq
คำสั่งเพื่อทำการเปรียบเทียบการอ้างอิงโดยตรง:
IL_0003: ldloc.0 // foo
IL_0004: ldnull
IL_0005: ceq
รหัส IL สำหรับfoo == null
ใช้การโทรไปยังโอเปอเรเตอร์ที่โอเวอร์โหลด:
IL_0016: ldloc.0 // foo
IL_0017: ldnull
IL_0018: call UserQuery+Foo.op_Equality
ดังนั้นความแตกต่างคือถ้าคุณใช้==
คุณเสี่ยงต่อการใช้รหัสผู้ใช้ (ซึ่งอาจมีพฤติกรรมที่ไม่คาดคิดหรือปัญหาประสิทธิภาพ)
ข้อ จำกัด เกี่ยวกับยาชื่อสามัญ
การใช้is null
โครงสร้าง จำกัด ประเภทให้เป็นประเภทอ้างอิง คอมไพเลอร์ทำให้มั่นใจในสิ่งนี้ซึ่งหมายความว่าคุณไม่สามารถใช้is null
กับประเภทค่าได้ หากคุณมีวิธีการทั่วไปคุณจะไม่สามารถใช้งานได้is null
เว้นแต่ว่าประเภททั่วไปถูก จำกัด ให้เป็นประเภทอ้างอิง
bool IsNull<T>(T item) => item is null; // Compile error: CS0403
bool IsNull<T>(T item) => item == null; // Works
bool IsNull<T>(T item) where T : class => item is null; // Works
ขอบคุณDavid Augusto Villa ที่ชี้ให้เห็น