В чем разница между "x равно нулю" и "x == null"?


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

if (x is null) return;

вместо

if (x == null) return;

есть ли какие-либо преимущества для использования нового способа (прежний пример), чем старый синтаксис?

семантика-другому?

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

ссылка.

2 128

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

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