我有一个同事,他喜欢写下他的空检查,如下所示:
if (!ReferenceEquals(myObject, null))
另一方面,我发现这种语法很难阅读并且更喜欢:
if (myObject != null)
我发现一些文章和堆栈溢出问题讨论了关于运算符重载的ReferenceEquals的优点,但在运算符重载方案之外,ReferenceEquals vs ==有什么好处?
答案 0 :(得分:36)
但是在运算符重载方案之外,ReferenceEquals与==?
有什么好处
不 - 明确使用Object.ReferenceEquals
的唯一优势(并且我认为它没有多大优势)将永远不会使用重载运算符equals。在非重载的情况下,== Operator被定义为“如果两个操作数引用同一个对象”,则返回“对于除”字符串以外的所有“引用类型”。因此,它的等价物(假设它没有超载)。
我个人也赞成使用第二种语法,并发现它对于null检查更易于维护。我还认为任何超载的operator==
也应该对null
进行适当的检查,如果由于某种原因(这可能是奇怪的)没有,那么可能会有特定的该决定背后的理由会导致您想要使用重载,而不是ReferenceEquals
。
答案 1 :(得分:26)
使用c#7,您可以使用:
if ( !(myObject is null) )
相当于
if (!ReferenceEquals(myObject, null))
答案 2 :(得分:5)
好吧,如果有人要覆盖==或!=运算符,他们可以让他们做任何他们想做的事情。甚至可以让它做一些真实的意思,如return true;
或return false;
。另外,如果有一个重载的运算符,它有可能不会像ReferenceEquals
那样表现良好(不能保证,而且可能不够重要,但仍然如此)。
话虽如此,由于任何重载运算符的任何合理实现,这根本不是问题。我个人不使用ReferenceEquals
,除非我有令人信服的理由不在该类型或特定情况下使用==
运算符。
答案 3 :(得分:2)
就空值检查而言,两者应始终返回相同的结果。如果非null引用永远等于null(即使使用Null对象模式),无论是否使用了ReferenceEquals或==运算符,它都是非常坏事。所以,在那种情况下我会使用== /!=。
我想说,如果==运算符被重载,使用ReferenceEquals 可能 更快。重载==应该做的第一件事是看两个变量是否指向同一个对象,所以在重载运算符的情况下,你最终会在调用堆栈上有一个额外的帧。使用ReferenceEquals还可以保证仅执行 检查。
我通常也会在几乎任何其他场景中使用== /!=。整个想法是运营商定义“平等”;这并不总是指称的(实际上,大多数复合对象应该在结构上进行比较以获得相等;如果它们的成员相等则它们是相等的)。从理论上讲,该对象知道如何最好地将自己与另一个对象进行比较,对于相等,相对顺序等,而不是硬编码一个非常具体且可能不正确的逻辑,你应该使用该语言的面向对象的本质来让对象告诉你它是否与其他任何东西相等。
答案 4 :(得分:1)
ReferenceEquals可能会稍快一些。如前所述,它确保不会调用重载的Equals运算符。此外,ReferenceEquals确保只执行一次比较而不是可能的2,具体取决于重载的Equals运算符的实现。虽然重载运算符很可能使用ReferenceEquals本身作为第一个语句。
我个人确实使用了ReferenceEquals,但仅限于我正在调整以挤出最后一个时钟周期的地方(可能每秒被称为数百万次的地方)。或者当我无法控制类型时,就像在泛型的情况下一样。 ......但只有当表现真的很重要时才会再次出现。
答案 5 :(得分:0)
VB.NET标签可能不应该包含在这个问题中,因为没有另外提及,但是,为了完整性,Is
等同于Object.ReferenceEquals
,因此可以始终使用那个电话。
答案 6 :(得分:0)
所以,尽管它已经有一百万年的历史了,但我还是想引起大家的注意。
假设我们要编写一个扩展方法来检查null。我们可以执行以下操作:
public static bool IsNull<T>(this T value) where T : class, new()
{
return value == null;
}
但是这段代码很无聊。
为什么T必须是一个类。为什么?因为我们不能将值类型与null进行比较。这使得编写体面的通用代码非常麻烦。
或者,您可以将相同的方法附加到对象上,而不必关心该对象是什么。
public static bool IsNull(this object value)
{
return object.ReferenceEquals(value, null);
}
这提供了其他可能性,例如为Linq编写容错单子或您拥有什么-而不实际限制通用代码。
答案 7 :(得分:0)
真的,我的回复很晚-但是我在阅读EFCore库时碰到了这篇文章,并且遇到了这种方法...
Microsoft.EntityFrameworkCore.Utilities中有一个Check类,该类使用此逻辑进行空检查。...
internal static class Check
{
[ContractAnnotation("value:null => halt")]
public static T NotNull<T>([NoEnumeration] T value, [InvokerParameterName] [NotNull] string parameterName)
{
#pragma warning disable IDE0041 // Use 'is null' check
if (ReferenceEquals(value, null))
#pragma warning restore IDE0041 // Use 'is null' check
{
NotEmpty(parameterName, nameof(parameterName));
throw new ArgumentNullException(parameterName);
}
return value;
}
答案 8 :(得分:0)
如其他答案所述,这两个调用的语义略有不同。
如果您想使用ReferenceEquals
的语义但使用简化的语法,对于引用类型,您还可以使用:
if (myObject is object)
答案 9 :(得分:0)
在 C# 9 中,您可以使用 if (myObject is not null)
。 The reference 声明以下安全保证:
当您将表达式与 null 匹配时,编译器保证不会调用用户重载的 == 或 != 运算符。