在.NET中,您需要Equals(object)和GetHashCode()兼容。但有时你不能:
public class GreaterThan32Bits
{
public int X { get; set; }
public int Y { get; set; }
}
因为数据密度大于32位,并且GetHashCode返回Int32,所以您将有3个解决方案(假设正确实现了GetHashCode):
避免代码重复 丢弃为不正确
public override bool Equals(object other)
{
if(ReferenceEquals(null, other)) return false;
if(ReferenceEquals(this, other)) return true;
return this.GetHashCode() == other.GetHashCode();
}
与GetHashCode()
分开实施Equalspublic override bool Equals(object obj)
{
if(ReferenceEquals(null, other)) return false;
if(ReferenceEquals(this, other)) return true;
var other = obj as GreaterThan32Bits;
if(this.X == other.X) return this.Y == other.Y;
return false;
}
实现更高精度的GetHashCode64,重写的GetHashCode(32位)将返回(int)GetHashCode64(),而Equals将返回this.GetHashCode64()== other.GetHashCode64()
你会实施哪一个?
第一个解决方案 imprecise 不正确,但更清晰。第二个选项看起来很干净,但是当类有更多属性时会变得非常复杂。第三种选择是妥协。
答案 0 :(得分:5)
要求如下: 如果(a.Equals(b)),那么a.GetHashCode()== b.GetHashCode()
不是相反。
你不应该在GetHashCode()方面实现Equals()。 GetHashCode完全有效,但Equals()不得返回误报。
我建议这样做:
public override int GetHashCode()
{
return unchecked( this.X * p1 + this.Y * p2 );
}
public override bool Equals(object obj)
{
var other = obj as GreaterThan32Bits;
// you must do the null test after the cast, otherwise the
// function crashes when obj is not a GreaterThan32Bits instance
if (ReferenceEquals(other, null)) return false;
return this.X == other.X && this.Y == other.Y;
}
其中p1和p2是大质数。这通常会产生良好的散列函数(少数散列碰撞 - >字典变得高效)。如果X和Y值是独立的(例如,你不希望像X = Y这样的直线上有很多点),那么像X ^ Y
这样简单的东西就可以成为一个很好的哈希函数。
但是,如果你真的将这个类用作字典(或其他哈希表)中的键,那么你只需要一个好的哈希函数。
实际上,总是在GetHashCode()中返回0并且只实现Equals()是完全没错的。 对于像键这样的对象,词典仍然可以正常工作,它只会效率低下。
答案 1 :(得分:4)
您的第一个实现是不正确。即使对象本身不相等,两个对象的哈希码也可能相等:这是哈希码的本质。
对象哈希码可能对确定两个对象不相等时有用,但要确定它们 是否相等,则必须调用.Equals()
GetHashCode()
总是返回0的实现是合法的,但当将该类型的对象插入到各种类型的容器中时,可能效率不高。
您的选项2是最佳选择。将Equals()
的实现与GetHashCode()
分开是一个好主意,因为它们做了很多不同的事情。当且仅当两个对象在所有方面都相同时,Equals()
必须返回true
。为此,您通常必须单独检查每个对象属性。
答案 2 :(得分:2)
严格来说,第一个解决方案不起作用。那不是解决方案。
哈希的想法完全不同。 Int32足以达到这个目的。
建议的GetHashCode()是
return X ^ Y;
简直就是这样。
编辑:等于方法然后可以使用GetHashCode(),但仅在哈希值不同时返回false。无论如何都需要深入比较。
答案 3 :(得分:1)
我认为你缺少的关键是GetHashCode()不必返回唯一值。
两个不同的对象返回相同的GetHashCode是完全可以接受的。假设您将两个对象添加到具有相同HashCode的HashSet,然后容器将首先使用GetHashCode查找对象所在的HashSet中的大致位置,然后在所有匹配对象上使用equals来查找您的确切对象。
如果每个对象都有唯一的哈希码,显然会更好。如果每个对象返回相同的hashCode,那么性能会很糟糕。