【问题标题】:Why do these two comparisons have different results?为什么这两个比较有不同的结果?
【发布时间】:2014-02-03 00:39:40
【问题描述】:

为什么这段代码返回true:

new Byte() == new Byte()   // returns true

但此代码返回 false:

new Byte[0] == new Byte[0] // returns false

【问题讨论】:

  • 我很惊讶没有人发现这个问题的重复,因为它是非常基本的 value 类型的诗句而不是 reference 类型的问题。
  • 我对它获得的赞成票数量感到更加惊讶——截至目前为 51 个。

标签: c# .net equality


【解决方案1】:

因为new Byte() 创建了值类型,它们按值进行比较(默认情况下它将返回byte 和值0)。而new Byte[0]创建数组,它是一个引用类型,通过引用进行比较(这两个数组实例会有不同的引用)。

详见Value Types and Reference Types文章。

【讨论】:

    【解决方案2】:

    字节在 .NET 中为 value types,这意味着当且仅当两个字节具有相同的值时,== 运算符才返回 true。这也称为value equality

    但数组在 .NET 中是 reference types,这意味着 == 运算符在且仅当它们引用内存中的相同数组实例时才返回 true。这也称为reference equality or identity

    请注意,== 运算符可以针对引用类型和值类型进行重载。例如,System.String 是一个引用类型,但字符串的 == 运算符会按顺序比较数组中的每个字符。见Guidelines for Overloading Equals() and Operator == (C# Programming Guide)

    如果您想测试数组是否包含完全相同的值(按顺序),您应该考虑使用Enumerable.SequenceEqual 而不是==

    【讨论】:

    • 我相信问题的症结在于== 运算符及其双重性质。这个答案清楚地涵盖了这一点。
    • 我喜欢将“默认”用于其他引用类型,但实际上是否可以更改数组类型的这种行为?
    • @ChrisHayes 否。运算符只能在为其定义的类中重载,并且由于 System.Array 类不提供重载,它使用默认的引用相等。您可能认为您可以创建自己的数组类型(System.Array 毕竟是抽象的),但编译器不允许您从它继承。不过,您可能会非常接近地使用隐式运算符将数组转换为另一种类型,但这个想法让我毛骨悚然。
    【解决方案3】:

    比较引用实际上是比较指针地址,这是不同的原因返回false和值地址无关它比较值。

    编译器尝试将值类型存储在寄存器中,但由于寄存器数量有限,进一步存储在堆栈中,值[Reference],而引用类型在堆栈中,但值在堆中保存内存地址的地址。

    这里的比较比较堆栈中存在的值,在第一种情况下两者相同,而在第二种情况下,它是不同的堆地址。

    【讨论】:

    • 这是一个非常令人困惑的答案。第一部分仍然使它看起来像一个参考比较,因为你仍然使用“指针”这个词。使用图形而不是文本也很烦人,因为这让我很难对其进行编辑以改进答案。
    • -1 用于延续“值类型存储在堆栈中”的神话。我原以为这两个new Byte() 调用的结果很可能存储在寄存器中。
    • @Damien_The_Unbeliever 寄存器存储取决于寄存器可用性,否则它存储在堆栈中,两种情况下的值相同。
    • 你的整个答案仍然是一个漫谈。值类型的关键方面是它们按值进行比较。该值存储在何处并不重要。您可以将两种值类型放入堆分配的结构中(有意或由于提升),并且比较仍将基于它们的值。
    【解决方案4】:

    == 运算符有一个重载,其中两个操作数都是byte 类型,并且实现了比较每个字节的值;在这种情况下,您有两个零字节,它们是相等的。

    == 运算符没有为数组重载,因此在第二种情况下使用了具有两个 object 操作数的重载(因为数组的类型为 object),并且它的实现比较了对两者的引用对象。两个数组的引用不同。

    值得注意的是,这与byte 是值类型而数组是引用类型这一事实(直接)无关。 byte== 运算符具有值语义only,因为该实现存在特定的运算符重载。如果该重载不存在,那么 就不会有两个字节作为有效操作数的重载,因此代码根本不会编译。通过创建自定义struct 并将它的两个实例与== 运算符进行比较,您可以很容易地看到这一点。除非您为这些类型提供自己的 == 实现,否则代码不会编译。

    【讨论】:

      猜你喜欢
      • 2015-06-13
      • 2019-02-24
      • 2019-12-18
      • 1970-01-01
      • 1970-01-01
      • 2013-08-27
      • 2021-12-10
      • 1970-01-01
      • 2020-01-03
      相关资源
      最近更新 更多