В чем разница между "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 nullconstant 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разница в том, что если вы используете
==вы рискуете запустить код пользователя (который может быть неисправен или иметь плохую производительность).