Яка різниця між "x is null" та "x == null"?


276

В C # 7 ми можемо використовувати

if (x is null) return;

замість

if (x == null) return;

Чи є якісь переваги щодо використання нового способу (колишнього прикладу) над старим?

Чи відрізняється семантика?

Це лише питання смаку? Якщо ні, коли я повинен використовувати один над іншим?

Довідка: Що нового в C # 7.0 .


4
це посилання, на яке я тільки дивився, однак воно не дає вам багато інформації, саме тому я думаю, що ОП задає питання. Найважливіша частина сторінки - це тест. Оператор Оператор "є" використовується для перевірки того, чи сумісний тип об'єкта з заданим типом чи ні. Іншими словами, ми використовуємо оператор "є" для перевірки того, що тип об'єкта є таким, яким ми його очікуємо. Давайте подивимось на його синтаксис:
Симон Ціна

2
@SimonPrice Йдеться про поточну версію C #: C # 6. Це питання стосується C # 7, який має відповідність шаблону .
Патрік Хофман

@bigown, яку деталь ви шукаєте?
Патрік Хофман

@PatrickHofman, тип карикатури, відповів на прикладі
Маньєро

Відповіді:


231

Оновлення: Компілятор Roslyn був оновлений, щоб зробити поведінку двох операторів однаковою, коли немає перевантаженого оператора рівності . Будь ласка, дивіться код у поточних результатах компілятора ( M1і M2в коді), який показує, що відбувається, коли немає порівняльного перевантаження рівності. Зараз вони обидві мають кращу ==поведінку. Якщо є порівняльний перевантажений рівність, код все одно відрізняється .

Нижче наведено аналіз старіших версій укладача Roslyn.


Бо nullнемає різниці з тим, до чого ми звикли з C # 6. Однак речі стають цікавими, коли ви переходите nullна іншу константу.

Візьмемо для прикладу:

Test(1);

public void Test(object o)
{
    if (o is 1) Console.WriteLine("a");
    else Console.WriteLine("b");
}

Вихід тесту a. Якщо порівнювати це з o == (object)1тим, що ви б написали нормально, це має певне значення. isвраховує тип з іншого боку порівняння. Це круто!

Я думаю , що == nullпроти is nullшаблону постійна тільки те , що добре знайомий «випадково», де синтаксис isоператора і дорівнює прибутковість оператора такого ж результату.


Як коментує svick , is nullдзвонить System.Object::Equals(object, object)куди ==дзвонитьceq .

ІЛ для is:

IL_0000: ldarg.1              // Load argument 1 onto the stack
IL_0001: ldnull               // Push a null reference on the stack
IL_0002: call bool [mscorlib]System.Object::Equals(object, object) // Call method indicated on the stack with arguments
IL_0007: ret                  // Return from method, possibly with a value

ІЛ для ==:

IL_0000: ldarg.1              // Load argument 1 onto the stack
IL_0001: ldnull               // Push a null reference on the stack
IL_0002: ceq                  // Push 1 (of type int32) if value1 equals value2, else push 0
IL_0004: ret                  // Return from method, possibly with a value

Оскільки ми говоримо про nullце, різниці немає, оскільки це має значення лише для випадків . Це може змінитися, якщо ви перевантажили оператора рівності.


15
@PatrickHofman Це схоже на isдзвінки object.Equals(x, null), а ==компілюється як ceq. Але результат повинен бути таким же, як ви сказали.
svick

16
Завжди майте на увазі, що ==це оператор, що завантажується. Ви можете мати будь-яку поведінку, яку ви хочете з цим. Наприклад, наприклад, цей дивно реалізований== звичай не скаже вам, чи справді ваш примірник дійсний. is nullз іншого боку, завжди повертатиметься правдою для справжніх нульових посилань :) Також, якщо у вас є ReferenceEqualsкод, лампочки VS 2017 запропонують змінити на is null, не == null(правильно).
nawfal

2
@PatrickHofman @svick два нульові перевірки тепер компілюються в одне і те ж, тому isбільше немає накладних витрат виклику функції при використанні для перевірки на null. Для доказу дивіться посилання, розміщене в коментарях @svick.
AndreasHassing

1
@ AndreasBjørnHassingNielsen Оновлено мою відповідь.
Патрік Хофман

2
@PatrickHofman чи не повинен ІЛ буде навпаки? == називає System.Object :: Дорівнює (об'єкт, об’єкт) і є нульовим викликом ceq
Zbigniew Ledwoń

67

Перевантажений дорівнює оператору

Насправді є різниця в семантиці між двома порівняннями, коли ви порівнюєте 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

Дякуємо Давидові Аугусто Віллі за те, що вказав на це.


2
Крім того, примітка (x є null) вимагає обмеження класу, якщо x є загальним типом, тоді як (x == null) та object.ReferenceEquals (x, null) цього не роблять.
Девід Аугусто Вілла
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.