为什么此代码返回true:
new Byte() == new Byte() // returns true
但此代码返回false:
new Byte[0] == new Byte[0] // returns false
答案 0 :(得分:143)
因为new Byte()
创建的值类型会按值进行比较(默认情况下,它会返回值为byte
的{{1}})。 0
创建数组,这是一个引用类型并通过引用进行比较(这两个数组实例将有不同的引用)。
有关详细信息,请参阅Value Types and Reference Types文章。
答案 1 :(得分:43)
.NET中的字节为value types,这意味着当且仅当两个字节具有相同值时,==
运算符才返回true。这也称为value equality。
但.NET中的数组是reference types,这意味着==
运算符返回true,当且仅当它们引用内存中的同一数组实例时才会返回true。这也称为reference equality or identity。
请注意,==
运算符可以为引用和值类型重载。例如,System.String
是引用类型,但字符串的==
运算符按顺序比较数组中的每个字符。请参阅Guidelines for Overloading Equals() and Operator == (C# Programming Guide)。
如果您想测试数组是否包含完全相同的值(按顺序),您应该考虑使用Enumerable.SequenceEqual
而不是==
。
答案 2 :(得分:10)
比较引用实际上是比较指针地址,这是不同的,这是返回false的原因,而在值地址无关紧要,它比较值。
编译器尝试将值类型存储在寄存器中,但由于寄存器数量有限,堆栈中的进一步存储发生值为[Reference],而引用类型位于堆栈中,但值保存堆中的内存地址。
比较在这里比较堆栈中存在的值,在第一种情况下对于两者都是相同的,而在第二种情况下,它是不同的堆的地址。
答案 3 :(得分:1)
==
运算符有一个重载,其中两个操作数的类型为byte
,并且它被实现为比较每个字节的值;在这种情况下,您有两个零字节,它们是相等的。
==
运算符没有为数组重载,因此在第二种情况下使用了具有两个object
操作数的重载(因为数组类型为object
),并且它的实现比较两个对象的引用。对两个数组的引用是不同的。
值得注意的是,这与({1}}是值类型且数组是引用类型的事实没有任何关系。 byte
的{{1}}运算符仅具有值语义 ,因为运算符具有该实现的特定重载。如果那个重载不存在那么 没有重载,其中两个字节将是有效的操作数,因此代码根本不会编译。通过创建自定义==
并将其两个实例与byte
运算符进行比较,您可以轻松地看到这一点。除非您为这些类型提供struct
的实现,否则代码将无法编译。