Подтвердить что ты не робот

В чем разница между "x is null" и "x == null"?

В С# 7 мы можем использовать

if (x is null) return;

вместо

if (x == null) return;

Есть ли преимущества использования нового способа (прежний пример) по сравнению со старым?

Семантика отличается?

Это просто вопрос вкуса? Если нет, когда я должен использовать один поверх другого?

Ссылка: Что нового в С# 7.0.

4b9b3361

Ответ 1

Обновление: компилятор Roslyn был обновлен, чтобы сделать поведение двух операторов одинаковым, когда нет перегруженного оператора равенства. Пожалуйста, смотрите ilr/K4Zwlgdg5gBAygTxAFwKYFsDcAoADsAIwBswBjGUogQxBBgGEYBvbGNmAge06JgFkAjAApOBAFapSyGAA8AlDAC8APlkwwdCMCJEcASC49 AJhHjJ0 UtUylimFp04AvkA== rel="nofollow noreferrer">код в результатах текущего компилятора (M1 и M2 в коде), который показывает, что происходит, когда нет перегруженного средства сравнения равенства. У них обоих теперь лучше поведение ==. Если имеется перегруженный компаратор равенства, код все равно будет другим.

Смотрите более ранние версии компилятора Roslyn ниже анализ.


Для null нет разницы с тем, к чему мы привыкли в С# 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 vs. is null константа просто очень знаком "случайно", где синтаксис оператора is оператор equals дают одинаковый результат.


Как прокомментировал svick, ilr/K4Zwlgdg5gBAygTxAFwKYFsDcAoADsAIwBswBjGUogQxBBgGEYBvbGNmAge06JgFkAjAApOBAFapSyGAA8AlDAC8APlkwwdCMCJEcASC49 AJhHjJ0 UtUylimFp04AvkA== rel="nofollow noreferrer"> is null вызывает System.Object::Equals(object, object) где == вызывает ceq.

IL для 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 для ==:

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, нет никакой разницы, поскольку это имеет значение только в случаях. Это может измениться, если вы перегружаете оператор равенства.

Ответ 2

На самом деле существует разница в семантике между двумя сравнениями. Крайний регистр проявляется, когда вы сравниваете 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

Таким образом, разница в том, что если вы используете == вы рискуете запустить пользовательский код (который потенциально может иметь неожиданное поведение или проблемы с производительностью).