В чем разница между "x равно нулю" и "x == null"?
В C# 7 мы можем использовать
if (x is null) return;
вместо
if (x == null) return;
есть ли какие-либо преимущества для использования нового способа (прежний пример), чем старый синтаксис?
семантика-другому?
Это просто дело вкуса? Если нет, то когда использовать тот или иной.
2 ответа:
обновление: компилятор 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
constant pattern-это просто что-то очень знакомое "случайно", где синтаксисis
оператор и оператор equals дают один и тот же результат.
как svick комментирует:
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_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
, нет никакой разницы, так как это имеет значение только на экземплярах. Это может измениться при перегрузке оператора равенства.
существует на самом деле разница в семантике между двумя сравнениями. Крайний случай представляет себя, когда вы сравниваете
null
С типом, который перегрузил==
оператора.
foo is null
будет использовать прямое сравнение ссылок для определения результата, тогда какfoo == null
будет, конечно, запустить перегруженный==
оператор, если он существует.в этом примере я ввел ошибку в перегруженных
==
оператор, заставляя его всегда возвращатьсяfalse
если второй аргумент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 condition is NOT met } public class Foo { public static bool operator ==(Foo foo1, Foo foo2) { if (object.Equals(foo2, null)) return false; 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
разница в том, что если вы используете
==
вы рискуете запустить код пользователя (который может быть неисправен или иметь плохую производительность).