在C#7中,我们可以使用
if (x is null) return;
if (x == null) return;

使用新方法(以前的示例)比旧方法有什么优势吗?语义有什么不同吗?
只是口味问题吗?如果没有,我什么时候应该在另一个上使用?
参考:C#7.0的新增功能。

评论

那就是我刚才正在查看的链接,但是它没有给您太多信息,这就是为什么我猜OP在问这个问题。页面上最重要的部分是此测试是否为Operator(运算符)“ is”运算符用于检查对象的运行时类型是否与给定类型兼容。换句话说,我们使用“ is”运算符来验证对象的类型是否符合我们的预期。让我们看一下它的语法:

@SimonPrice这与C#的当前版本有关:C#6。此问题与C#7有关,它具有模式匹配。

@bigown您要寻找什么样的细节?

@PatrickHofman以示例的方式回答了

#1 楼

更新:Roslyn编译器已更新,以在没有重载相等运算符时使两个运算符的行为相同。请查看当前编译器结果中的代码(代码中的M1M2),其中显示了没有重载的相等比较器时会发生的情况。它们现在都具有性能更好的==行为。如果有一个重载的相等比较器,则代码仍然会有所不同。与使用C#6的习惯有所不同。但是,将null更改为另一个常量时,事情变得很有趣。例如,
/>
测试得出null。如果将其与通常编写的内容相比较,那确实会有所不同。 a考虑了比较另一侧的类型。

我认为o == (object)1is常数模式只是“偶然”而已,在这种情况下,== null运算符和equals运算符的语法会产生相同的结果。 br />

svick评论,is null调用isis null调用System.Object::Equals(object, object)==的IL:

Test(1);

public void Test(object o)
{
    if (o is 1) Console.WriteLine("a");
    else Console.WriteLine("b");
}


由于我们正在讨论ceq,因此没有区别,因为这仅对实例有所不同。当重载等于运算符时,这可能会改变。

评论


@PatrickHofman看起来像是调用object.Equals(x,null),而==编译为ceq。但是结果应该和您说的一样。

– svick
16年11月18日在16:04

始终谨记==是可重载的运算符。您可以使用它进行任何操作。例如这个怪异的实现==不会告诉您您的实例是否真正为空。另一方面,如果为null,则始终为true的null引用返回true :)此外,如果代码中包含ReferenceEquals,则VS 2017灯泡将建议更改为null,而不是== null(正确)。

– nawfal
18年4月19日在13:21

@PatrickHofman @svick现在可以将两个空检查编译为同一件事,因此在用于检查空值时不再具有函数调用的开销。为了证明,请参阅@svick在评论中发布的链接。

– AndreasHassing
18年6月11日在12:48

@AndreasBjørnHassingNielsen更新了我的答案。

–帕特里克·霍夫曼(Patrick Hofman)
18年6月12日在7:46

@PatrickHofman应该不是IL吗? ==调用System.Object :: Equals(object,object)并且为null调用ceq

– ZbigniewLedwoń
19-4-23在6:36



#2 楼

重载的equals运算符

在将null与已重载==运算符的类型进行比较时,两个比较之间实际上在语义上存在差异。 foo is null将使用直接引用比较来确定结果,而foo == 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);
    }

    // ...
}


null的IL代码使用foo is null指令执行直接引用比较:
IL_0003:  ldloc.0     // foo
IL_0004:  ldnull      
IL_0005:  ceq


ceq的IL代码使用对重载运算符的调用:

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


所以区别在于,如果您使用foo == null可能会冒着运行用户代码的风险(这可能会导致意外的行为或性能问题)。 。编译器会确保这一点,这意味着您不能在值类型上使用==。如果您有通用方法,除非将通用类型限制为引用类型,否则将无法使用is null。感谢David Augusto Villa提供的指出这一点。

评论


另外,如果x是泛型类型,则注释(x为null)需要类约束,而(x == null)和object.ReferenceEquals(x,null)则不需要类约束。

–大卫·奥古斯托·维拉
19年11月5日在23:58

#3 楼

当您尝试将非null变量与null值进行比较时,也存在差异。使用==时,编译器将发出警告,而使用is时,编译器将发出错误。最有可能在99%的时间里,您希望编译器对这种基本错误大喊大叫。为is null +1。


已通过NetCore3.1在https://dotnetfiddle.net/上进行了测试