GetHashCode 应该取决于类型吗?
首先,我使用所描述的 GetHashCode 算法,此处。现在,想象以下(人为的)示例:
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
或使用 Distinct
方法,并且这两个实例将被视为相同。
我可能只是误解了 GetHashCode 的使用,但我希望这两个实例具有不同的哈希码。这是无效的期望还是应该 GetHashCode
在计算中使用该类型? (或者 DerivedClass
也应该覆盖 GetHashCode
)吗?
PS我意识到有很多很多与这个主题相关的问题,但我还没有发现一个直接回答这个问题的问题。
Firstly, I'm using the GetHashCode
algorithm described, here. Now, picture the following (contrived) example:
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)
{
}
}
If I have a Foo
and a DerivedFoo
with the same values for each of the properties they're going to have the same hash code. Which means I could have HashSet<Foo>
or use the Distinct
method in Linq and the two instances would be treated as if they were the same.
I'm probably just misunderstanding the use of GetHashCode
but I would expect these the two instances to have different hash codes. Is this an invalid expectation or should GetHashCode
use the type in the calculation? (Or should DerivedClass
also override GetHashCode
)?
P.S. I realize there are many, many questions on SO relating to this topic, but I've haven't spotted one that directly answers this question.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
GetHashCode()
不应该保证唯一性(尽管尽可能唯一有助于提高性能)。GetHashCode()
的主要规则是等效对象必须具有相同的哈希码,但这并不意味着非等效对象不能 strong> 具有相同的哈希码。如果两个对象具有相同的哈希码,则调用
Equals()
方法来查看它们是否相同。由于类型不同(当然取决于您对 Equals 重载的编码方式),它们不会相等,因此不会有问题。即使如果每种类型都有不同的哈希码算法,仍然有可能发生冲突,因此也需要
Equals()
检查。现在给出上面的示例,您不实现
Equals()
这将使每个对象都不同,无论哈希码如何,因为Equals()
的默认实现object 是一个引用相等性检查。如果您还没有,请继续为您的每种类型重写
Equals()
(如果您愿意,它们可以继承您的GetHashCode()
实现,或者有新的),您可以在声明它们相等之前确保比较对象的类型相同。并确保Equals()
和GetHashCode()
始终实现,以便:Equals()
的对象必须 具有相同的GetHashCode()
结果。GetHashCode()
的对象必须不为Equals()
。GetHashCode()
is not supposed to guarantee uniqueness (though it helps for performance if as unique as possible).The main rule with
GetHashCode()
is that equivalent objects must have the same hash code, but that doesn't mean non-equivalent objects can't have the same hash code.If two objects have the same hash code, the
Equals()
method is then invoked to see if they are the same. Since the types are different (depending on how you coded your Equals overload of course) they will not be equal and thus it will be fine.Even if you had a different hash code algorithm for each type, there's still always a chance of a collision, thus the need for the
Equals()
check as well.Now given your example above, you do not implement
Equals()
this will make every object distinct regardless of the hash code because the default implementation ofEquals()
fromobject
is a reference equality check.If you haven't, go ahead and override
Equals()
for each of your types as well (they can inherit your implementation ofGetHashCode()
if you like, or have new ones) and there you can make sure that the type of the compare-to object are the same before declaring them equal. And make sureEquals()
andGetHashCode()
are always implemented so that:Equals()
must have sameGetHashCode()
results.GetHashCode()
must not beEquals()
.两个实例不需要具有不同的哈希码。 GetHashCode 的结果不由 HashSet 或其他框架类假定,因为即使在类型内也可能存在冲突。 GetHashCode 仅用于确定哈希表中存储项目的位置。如果 HashSet 中存在冲突,则会依靠 Equals 方法的结果来确定唯一匹配。这意味着无论您在何处实现 GetHashCode,您还应该实现 Equals(并检查类型是否匹配)。同样,每当你实现 Equals 时,你也应该实现 GetHashCode。请参阅 Eric Lippert 的精彩解释
The two instances do not need to have different hash codes. The results of GetHashCode are not assumed by the HashSet or other framework classes, because there can be collisions even within a type. GetHashCode is simply used to determine the location within the hash table to store the item. If there is a collision within the HashSet, it then falls back on the result of the Equals method to determine the unique match. This means that whever you implement GetHashCode, you should also implement Equals (and check that the types match). Similarly, whenever you implement Equals, you should also implement GetHashCode. See a good explanation by Eric Lippert here.