Equals和GetHashCode方法中的不一致性问题

13

阅读完这个问题Why do "int" and "sbyte" GetHashCode functions generate different values?后,我想进一步了解以下行为:

sbyte i = 1;            
int j = 1;
object.Equals(i, j) //false (1)
object.Equals(j, i) //false (2) 
i.Equals(j) //false (3)
j.Equals(i) //true (4)
i == j //true (5)
j == i //true (6)
i.GetHashCode() == j.GetHashCode() //false (7)
  1. (3)和(4)之间的区别违反了Equals应该是对称的要求。
  2. (2)和(4)之间的区别与MSDN规范不一致,规范说:

    如果两个对象不代表相同的对象引用并且都不为null,则会调用objA.Equals(objB)并返回结果。这意味着如果objA重写了Object.Equals(Object)方法,则会调用此重写。

  3. (3)和(5)之间的区别意味着操作符==返回true,但是从Equals的角度来看,对象并不相等。
  4. (4)、(5)、(6)和(7)之间的区别意味着两个对象在操作符==和Equals方面相等,但它们具有不同的哈希码。

我非常想知道是否有人可以解释为什么在相当基本的.NET类型中观察到这种我认为不一致的行为。


当我看到那个时,这就是我所想的。非常感谢您看到了问题的核心。 - Eric Javier Hernandez Saura
1
所有这些“不一致性”都源于从sbyte到int的隐式转换。 - H H
@pst a.Equals((object)b) 明确意味着 a.GetHashCode()==b.GetHashCode()。我会称任何类型,如果==Equals的行为不同,即使 .net 不严格要求这样做,也是有问题的。(忽略隐式转换,并假设运行时类型和静态类型相同) - CodesInChaos
1个回答

15

你的问题在于你忽略了在 i.Equals(j) 中的隐式转换。它会调用到重载的 int.Equals(int)。这里你正在比较 i(int)j,它们是相同的东西。对于 == 也会发生同样的隐式转换。

其他的比较操作涉及到一个 int 和一个 sbyte,根据定义它们是不同的。j.Equals(i) 调用的是重载的 int.Equals(object),因为参数不能隐式地转换成 sbyte

对于它们而言,Equals 是对称的,但是你的调用代码不是。如果你使用 i.Equals((object)j) 来去除隐式转换,它将返回 false,表明 Equals 是对称的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接