当我写这篇文章时:
ReferenceEquals(x, null)
Visual Studio建议
null check可以简化。
并将其简化为
x is null
那些真的一样吗?
答案 0 :(得分:7)
我注意到很多答案,指出x == null
,x is null
和ReferenceEquals(x, null)
都是等效的-在大多数情况下,这是对的。但是,在某些情况下,您不能使用x == null
,如下所述:
请注意,以下代码假定您已为类实现了Equals方法:
请勿执行此操作-递归调用操作符==方法,直到发生堆栈溢出:
public static bool operator ==(MyClass x1, MyClass x2)
{
if (x1 == null)
return x2 == null;
return x1.Equals(x2)
}
执行此操作:
public static bool operator ==(MyClass x1, MyClass x2)
{
if (x1 is null)
return x2 is null;
return x1.Equals(x2)
}
或
public static bool operator ==(MyClass x1, MyClass x2)
{
if (ReferenceEquals(x1, null))
return ReferenceEquals(x2, null);
return x1.Equals(x2)
}
答案 1 :(得分:3)
那些真的一样吗?
语义上是(假设x
不是值类型)。您正在对所有引用类型执行空检查。
实施:没有。 x == null
或x is null
将直接作为IL指令实施,但Object.ReferenceEquals(x, null)
将是方法调用。 1
另请注意,如果x
的类型已被覆盖operator ==
,那么x == null
可能不等效(在运算符重载中更改空值检查的语义充其量只是代码不佳,因为没有人期望这样的语义变化。)
1 当然,优化者可以识别出这个并输出IL,你需要查看IL以确认这一点。
答案 2 :(得分:1)
我意识到我很喜欢参加聚会,并且已经给出了答案,但是我觉得有必要总结一下,因为这是我每8-12个月左右要搜索一次的事情,希望有一个我能理解的解释(希望能得到发布)。
这是一种经过实践检验的方法,可以执行安全的引用相等性比较。它基本上执行(object)a == (object)b
(或类似的操作),并且具有可以立即识别其使用且不能覆盖的优点。
这种方法对大多数人来说是“自然的”(因为在整个C#中完成的大多数比较都将使用此运算符完成)。
引用类型的默认行为应正确。但是,这可能会过载,从而导致意外结果(想象操作员过载的执行失败)。
就像@mdebeus所说的那样,另外的风险(尽管对于阅读C#底漆的胜任的猴子来说还是很小的)正在引起StackOverflowException
。当重载==和!=并使用方法本身内部的运算符时,会出现这种情况。
好的,这是我们得到的一种闪亮的含糖新事物。 Microsoft在这种情况下描述 is :
is运算符检查表达式结果的运行时类型是否与给定类型兼容。
[...]
如果E的结果为非null并且E的T表达式返回true 可以通过参考转换(拳击)转换为T型 转换或拆箱转换;否则,它返回false。 is运算符不考虑用户定义的转换。
(阅读完整的说明here)
简而言之,如果可以通过装箱,拆箱或协方差通过b转换a,则它将返回true。 如您所料,这对null效果很好。
总而言之,作为个人说明,尽管是使等式重载中的空检查变得更短,更漂亮,但我认为我仍然会使用ReferenceEquals,这仅仅是因为我是一个控件-freak,至少有一部分 的工作方式使我担心协方差情况。
答案 3 :(得分:0)
在这种情况下他们的意思相同,是的。大多数人会使用x == null
。
我猜ReferenceEquals
可能有点令人困惑,因为实际上null
是一个文字,意味着根本没有参考。任何引用如何等于无引用?
请注意,x is null
仅适用于C#7且pattern matching feature。通常,您使用is
检查x
是否为兼容类型,但null
不是类型。所以这也有点令人困惑。
这就是我更喜欢x == null