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

if (x is null) return;

вместо

if (x == null) return;

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

Есть ли другая семантика?

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

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

Ответы (3)

Обновление: Компилятор 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, что вы бы написали нормально, это действительно имеет огромное значение.равно, учитывает тип с другой стороны сравнения. Это круто!

Я думаю, что == null vs. is null шаблон констант - это что-то очень знакомое «случайно», где синтаксис равен * 100007 Оператор * и оператор равенства дают одинаковый результат.


Как svick прокомментировано, равно нулю вызывает System.Object :: Equals (объект, объект) где == звонки ceq.

IL для это:

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

Существует также разница, когда вы пытаетесь сравнить ненулевую переменную с нулевым значением. При использовании ==компилятор выдаст предупреждение, а при использовании -компилятор выдаст ошибку. Скорее всего, в 99% случаев вы хотите, чтобы компилятор кричал на вас за такую ​​простую ошибку. +1 для равно нулю.

enter image description here

enter image description here

П.С. Проверено на https://dotnetfiddle.net/ с NetCore3.1

Overloaded equals operator

There is in fact a difference in semantics between the two comparisons when you are comparing null with a type that has overloaded the == operator. foo is null will use direct reference comparison to determine the result, whereas foo == null will of course run the overloaded == operator if it exists.

In this example I have introduced a "bug" in the overloaded == operator, causing it to always throw an exception if the second argument is 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);
    }

    // ...
}

The IL code for foo is null uses the ceq instruction to perform a direct reference comparison:

IL_0003:  ldloc.0     // foo
IL_0004:  ldnull      
IL_0005:  ceq

The IL code for foo == null uses a call to the overloaded operator:

IL_0016:  ldloc.0     // foo
IL_0017:  ldnull      
IL_0018:  call        UserQuery+Foo.op_Equality

So the difference is, that if you use == you risk running user code (which can potentially have unexpected behavior or performance problems).

Restriction on generics

Using the is null construct restricts the type to a reference type. The compiler ensures this, which means you cannot use is null on a value type. If you have a generic method, you will not be able to use is null unless the generic type is constrained to be a reference type.

bool IsNull(T item) => item is null;                  // Compile error: CS0403
bool IsNull(T item) => item == null;                  // Works
bool IsNull(T item) where T : class => item is null;  // Works

Thanks to David Augusto Villa for pointing this out.

2022 WebDevInsider