【问题标题】:How to treat nulls in equality comparisons?如何处理相等比较中的空值?
【发布时间】:2010-11-20 17:27:13
【问题描述】:

当我必须为

实现相等比较器时
public class SampleClass
{
    public int Prop { get; set; }
}

我应该做

null == new SampleClass() 

new SampleClass() == null

new SampleClass().Equals(null)

假的?

然后呢

new SampleClass() != null

应该也是假的吧?

更新人们质疑这个问题背后的原因。应该是这样 != 和 == 总是相反的。但是,如果我实现了这些方法,所以上面的所有比较结果都是错误的,那么 == 和 != 运算符将产生相同的结果。所以 != 应该返回 true 还是 false 是一个两难的选择。

【问题讨论】:

    标签: c# .net operators iequatable equals-operator


    【解决方案1】:

    我认为这是一个特别有趣的问题。我对此的看法与任何答案都不完全相同,所以请耐心等待我这么晚才来。

    首先要注意的是,.NET 中的 null 与其他一些上下文中的 null 并不完全相同,尽管它可以用来对它们进行建模。

    以SQL为例,我们可能有1 = null1 <> null都返回null,因为null的概念更接近数学,其中null不等于任何东西,包括null,但是也不是完全不等于任何东西。

    如果需要,我们可以为此使用 C# null,但这并不是 .NET 中 null 的默认含义的工作方式。

    对于任何引用类型,null 具有特定定义的含义,并且可能具有上下文提供的其他含义。

    具体意思是“这个类型的对象没有this的实例”。

    在给定上下文中的其他含义可能是“整数值实际上是 null,而不是匹配任何整数”,或者“没有这样的项目集合,甚至没有一个空集合”,或者“这是第一个这样的项目,所以没有更早的”等等,这取决于我们如何使用它。 (另外,它可能意味着“哦,亲爱的,那真的不应该为空,最好抛出异常”)。

    现在,我们可能想要大量使用这些额外的含义,以至于我们定义了对象等于 null 或至少不等于 null 有意义的情况。但是,我们有以下限制:

    1. 对于引用类型的值的 null 意味着没有该引用类型的实例的具体定义不会消失。

    2. 对于给定的 x 和 y,x == y 将始终给出与 x != y 相反的结果的语义不会消失。

    因此:

    1. 如果我们想要一个实例可以等于null的类型,它必须是值类型。

    2. 我们仍然必须让 x != null 返回与 x == null 的相反值。

    现在,从 .NET 2.0 开始,我们已经有了一个可以做到这一点的内置函数:Nullable<T>(或 C# 语法中的 T?)。它还有一些额外的支持来帮助它在面对拳击时表现良好(这使得它在人的方式上表现得像一个引用类型,所以如果没有额外的支持,我们就会遇到麻烦,x == null 将返回 true 但@ 987654336@ 将返回 false。

    同样如此,Nullable<T> 几乎可以处理任何我们想对 null 使用这种稍微不同的语义的情况,这意味着我们真的没有任何情况了。可能需要定义一个 Equals() 方法,当传递 null 时返回 true。

    【讨论】:

      【解决方案2】:

      除上述内容外,请注意:

      预定义的引用类型相等运算符有:

      bool operator ==(object x, object y);
      bool operator !=(object x, object y);
      

      所以....

      SampleClass a = null;
      SampleClass b = null;
      
      • a == b 为真
      • a != b 是假的

      阅读 .NET 框架设计者对这个问题的看法:

      Why don't nullable relational operators return “bool?” instead of “bool“?

      欲了解更多信息,请阅读:

      【讨论】:

        【解决方案3】:

        您的示例中所有与 null 的相等比较绝对应该是错误的。最后一个也很重要:

        new SampleClass() != null
        

        这必须肯定评估为true,因为这是检查引用变量是否已初始化的常用方法。如果它被评估为false,它可能会无意中在整个地方重新分配变量,因为 C# 开发人员期望那里的操作符有某种行为。另一个例子:

        SampleClass myVar = new SampleClass();
        
        // Various stuff happening here, possibly setting myVar to null
        
        if (myVar != null)
        {
            // Programmer go "WTFBBQ?" when he finds this doesn't get executed
            myVar.DoStuff();
        }
        

        一头雾水,程序员把这个改成:

        if (myVar == null)
        {
            myVar = new SampleClass();
        }
        
        myVar.DoStuff(); // null reference exception, huh?
        

        【讨论】:

          【解决方案4】:

          这甚至是一个问题吗?不,null 永远不应该等于一个对象。

          编辑: 因此,通过扩展,new SampleClass() != null 应该是 truenull 不像 NaN;它的定义非常明确。

          【讨论】:

            【解决方案5】:

            Null 永远不应与非 null 引用进行比较。通过扩展,您的 != 应该返回 true,因为它与等式相反。

            【讨论】:

              【解决方案6】:

              如果你有一个对象的实例,你就没有 null 并且所有的相等比较器都应该尊重这一点。

              【讨论】:

                【解决方案7】:

                正如其他人所说,null 永远不能等于包括 null 在内的任何其他值。这是因为 null 不是值,而是缺少值。

                对于您的具体问题,您似乎正在尝试实例化一个尚未初始化的对象,并且您想确定该对象是否已被初始化。我的建议是包含一个指示对象是否已初始化的属性。

                【讨论】:

                • null 应该等于 null :P
                • “null 永远不能等于任何其他内容,包括 null”与“null 应该等于 null”谁能决定?
                • null 不等于 null 在关系数据库中可能很常见,但在 C# 中却毫无意义。 if (myVar == null) myVar = new SampleClass();。如果 null 不等于 null,那将初始化变量。
                • 在数据库中,null != null。在 C# 中,null == null。这两种类型的null的含义是不一样的。
                • null 绝对应该等于null。正如我在编辑中所说,它不像NaN
                【解决方案8】:

                我不确定我是否完全理解您的问题,但 null (根据定义)不是一个值。因此,

                null == new SampleClass()
                

                真的没有任何意义(而且,真的,其他比较都没有)。

                你能改写你的问题吗?

                【讨论】:

                  猜你喜欢
                  • 2011-05-18
                  • 2016-12-29
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-06-18
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多