在C#7中,我们可以使用
if (x is null) return;
而不是
if (x == null) return;
使用新方式(前一个例子)是否有任何优势?
语义是否有所不同?
只是品味问题?如果没有,我何时应该使用另一个?
答案 0 :(得分:147)
更新:当没有重载的相等运算符时,Roslyn编译器已更新为使两个运算符的行为相同。请参阅代码中的code in the current compiler results(M1
和M2
),其中显示了没有重载的相等比较器时会发生什么。他们现在都有更好的==
行为。如果存在重载的等式比较器the code still differs。
请参阅以下分析的旧版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
常量模式只是非常熟悉的事情'其中is
运算符的语法和equals运算符产生相同的结果。
由svick评论,is null
calls System.Object::Equals(object, object)
where ==
calls 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 ==
:
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
,因此only makes a difference on instances没有区别。当你重载了相等运算符时,这可能会改变。
答案 1 :(得分:41)
事实上,两种比较之间存在语义差异。当您将null
与重载==
运算符的类型进行比较时,边缘情况会出现。
foo is null
将使用直接引用比较来确定结果,而foo == null
当然会运行重载的==
运算符(如果存在)。
在这个例子中,我在重载的==
运算符中引入了一个“bug”,如果第二个参数是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);
}
// ...
}
foo is null
的IL代码使用ceq
指令执行直接引用比较:
IL_0003: ldloc.0 // foo
IL_0004: ldnull
IL_0005: ceq
foo == null
的IL代码使用对重载运算符的调用:
IL_0016: ldloc.0 // foo
IL_0017: ldnull
IL_0018: call UserQuery+Foo.op_Equality
所以区别在于,如果您使用==
,则存在运行用户代码(可能会出现意外行为或性能问题)的风险。
答案 2 :(得分:2)
当您尝试将非null变量与null值进行比较时,也存在差异。使用==
时,编译器将发出警告,而使用is
时,编译器将发出错误。最有可能在99%的时间里,您希望编译器针对这种基本错误大喊大叫。为is null
+1。
P.S。已通过NetCore3.1在https://dotnetfiddle.net/上进行了测试