C# 是";ReferenceEquals(myObject,null)";“比”更好的实践;myObject==null";?

C# 是";ReferenceEquals(myObject,null)";“比”更好的实践;myObject==null";?,c#,.net,vb.net,C#,.net,Vb.net,我有一个同事非常喜欢写空支票,如下所示: if (!ReferenceEquals(myObject, null)) 一、 另一方面,您会发现这种语法很难阅读,并且更喜欢: if (myObject != null) 我发现一些文章和堆栈溢出问题讨论了ReferenceEquals在操作符重载方面的优点,但是在操作符重载场景之外,ReferenceEquals vs==有什么好处吗 但是在操作符重载场景之外,ReferenceEquals vs==有什么好处吗 否-显式使用Object.Re

我有一个同事非常喜欢写空支票,如下所示:

if (!ReferenceEquals(myObject, null))
一、 另一方面,您会发现这种语法很难阅读,并且更喜欢:

if (myObject != null)
我发现一些文章和堆栈溢出问题讨论了ReferenceEquals在操作符重载方面的优点,但是在操作符重载场景之外,ReferenceEquals vs==有什么好处吗

但是在操作符重载场景之外,ReferenceEquals vs==有什么好处吗

否-显式使用
Object.ReferenceEquals
唯一的优势(我认为这不是什么优势)是它永远不会使用重载运算符equals。在非重载情况下,对于所有“除字符串以外的引用类型”,将定义为“如果其两个操作数引用同一对象,则返回true”。因此,其等效项(前提是其未重载)


一、 就个人而言,我们也喜欢使用第二种语法,并发现它更易于维护,以进行空检查。我还认为,任何重载的
运算符==
也应该提供针对
null
的适当检查,如果由于某种原因(这很奇怪),它没有提供检查,那么该决定背后可能有一个特定的理据,这将导致您希望使用重载,而不是
引用equals
,如果有人要覆盖==或!=他们可以让他们做任何他们想做的事。他们甚至可以让它做一些真正的事情,比如
返回true
返回false。此外,如果存在重载运算符,则很有可能它的性能不如
ReferenceEquals
(不保证,可能还不够重要,但仍然如此)


话虽如此,因为对于任何重载操作符的合理实现,这根本不可能是一个问题。我个人不使用
ReferenceEquals
,除非我有充分的理由不在该类型或特定实例中使用
=
运算符。

就空检查而言,两者应始终返回相同的结果。如果一个非null引用曾经等于null(即使在使用null对象模式时),无论是使用ReferenceEquals还是==操作符,这都是一件非常糟糕的事情。因此,在这种情况下,我将使用==/!=

我想说,如果==运算符重载,使用ReferenceEquals可能会稍微快一点。重载==应该做的第一件事是查看两个变量是否指向同一个对象,因此在重载运算符的情况下,调用堆栈上会有一个额外的帧。使用ReferenceEquals还可以保证这是唯一执行的检查


我通常也会使用==/!=在几乎任何其他情况下。整个想法是运算符定义“相等”;这并不总是引用的(事实上,大多数复合对象都应该在结构上进行相等比较;如果它们的成员相等,它们就相等)。从理论上讲,对象知道如何最好地将自己与另一个对象进行比较,以获得相等性、相对顺序等,而不是硬编码一个非常具体且可能不正确的逻辑片段,您应该使用语言的面向对象特性,让对象告诉您它是否等于其他任何东西。

VB.NET标记可能不应该包含在这个问题中,因为它没有被提及,但是为了完整性,
Is
相当于
对象。ReferenceEquals
因此始终可以用来代替该调用。

ReferenceEquals可能会稍微快一点。如前所述,它确保没有重载的Equals操作符被调用。此外,ReferenceEquals确保只执行一次比较,而不是可能执行2次比较,具体取决于重载Equals运算符的实现。尽管重载运算符很可能使用ReferenceEquals本身作为第一条语句

我个人确实使用ReferenceEquals,但仅在我真正调整以挤出最后时钟周期的地方(可能被称为每秒数百万次的地方)。或者当我无法控制类型时,比如泛型。。。但同样,只有在性能非常关键的情况下。

对于c#7,您可以使用:

if ( !(myObject is null) )
相当于

if (!ReferenceEquals(myObject, null))

所以,我想插嘴这段对话,尽管它已经有一百万年的历史了

假设我们想要编写一个检查null的扩展方法。我们可以做到以下几点:

public static bool IsNull<T>(this T value) where T : class, new()
{ 
   return value == null;
}

这打开了其他的可能性,比如为Linq编写容错Monad,或者你有过什么,而不限制你的泛型代码。

真的,真的很晚才回复-但是我在阅读EFCore库时读到了这篇文章,发现了这个方法

Microsoft.EntityFrameworkCore.Utilities中有一个检查类,它使用此逻辑进行空检查

        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;
        }
内部静态类检查
{
[ContractAnnotation(“value:null=>halt”)]
公共静态T NotNull([NoEnumeration]T值,[InvokerParameterName][NotNull]字符串参数名称)
{
#pragma warning disable IDE0041//使用“为空”检查
if(ReferenceEquals(value,null))
#pragma warning restore IDE0041//使用“为空”检查
{
NotEmpty(parameterName,nameof(parameterName));
抛出新ArgumentNullException(parameterName);
}
返回值;
}

如其他答案所述,这两个调用的语义略有不同

如果您想使用
ReferenceEquals的语义,但语法简化,对于引用类型,您还可以使用:

if (myObject is object)
使用C#9,如果(myObject不为null),则可以使用
if (myObject is object)