Перевантажений дорівнює оператору
Насправді є різниця в семантиці між двома порівняннями, коли ви порівнюєте 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);
}
// ...
}
Іл-код для 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
Дякуємо Давидові Аугусто Віллі за те, що вказав на це.