首先,我使用的是GetHashCode
算法here。现在,想象下面的(人为的)例子:
class Foo
{
public Foo(int intValue, double doubleValue)
{
this.IntValue = intValue;
this.DoubleValue = doubleValue;
}
public int IntValue { get; private set; }
public double DoubleValue { get; private set; }
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = hash * 23 + IntValue.GetHashCode();
hash = hash * 23 + DoubleValue.GetHashCode();
return hash;
}
}
}
class DerivedFoo : Foo
{
public DerivedFoo(int intValue, double doubleValue)
: base(intValue, doubleValue)
{
}
}
如果我为每个属性设置了Foo
和DerivedFoo
,则它们将具有相同的哈希码。这意味着我可以在Linq中使用HashSet<Foo>
或使用Distinct
方法,这两个实例将被视为相同。
我可能只是误解了GetHashCode
的使用,但我希望这两个实例具有不同的哈希码。这是一个无效的期望还是GetHashCode
在计算中使用该类型? (或DerivedClass
还应覆盖GetHashCode
)?
P.S。我意识到关于这个主题的SO有很多很多问题,但是我没有发现直接回答这个问题的问题。
答案 0 :(得分:6)
GetHashCode()
不应该保证唯一性(尽管如果它尽可能独特,它会有助于提高性能)。
GetHashCode()
的主要规则是等效对象必须具有相同的哈希码,但这并不意味着非等效对象不能具有相同的哈希码。
如果两个对象具有相同的哈希码,则调用Equals()
方法以查看它们是否相同。由于类型不同(取决于你如何编码你的Equals过载),它们将不相等,因此它会没问题。
即使如果你对每种类型都有不同的哈希码算法,仍然总是有可能发生冲突,因此也需要进行Equals()
检查。
现在给出上面的示例,您不实现Equals()
这将使每个对象都不同,无论哈希代码如何,因为来自Equals()
的{{1}}的默认实现是引用相等性检查。
如果还没有,请继续为每个类型覆盖object
(如果您愿意,可以继承Equals()
的实施,或者有新的){在声明它们相等之前,确保compare-to对象的类型相同。并确保始终实施GetHashCode()
和Equals()
,以便:
GetHashCode()
的对象必须具有相同的Equals()
结果。GetHashCode()
的对象必须不为GetHashCode()
。答案 1 :(得分:1)
这两个实例不需要具有不同的哈希码。 HashSet或其他框架类不假定GetHashCode的结果,因为即使在类型中也可能发生冲突。 GetHashCode仅用于确定哈希表中用于存储项目的位置。如果HashSet中存在冲突,则它会回退到Equals方法的结果以确定唯一匹配。这意味着当您实现GetHashCode时,您还应该实现Equals(并检查类型是否匹配)。同样,每当实现Equals时,您还应该实现GetHashCode。请参阅Eric Lippert here的一个很好的解释。