GetHashCode 应该取决于类型吗?

发布于 2024-12-03 08:39:46 字数 1238 浏览 4 评论 0原文

首先,我使用所描述的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

何以畏孤独 2024-12-10 08:39:46

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 of Equals() from object 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 of GetHashCode() 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 sure Equals() and GetHashCode() are always implemented so that:

  • Objects that are Equals() must have same GetHashCode() results.
  • Objects with different GetHashCode() must not be Equals().
╭ゆ眷念 2024-12-10 08:39:46

两个实例不需要具有不同的哈希码。 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文