3

首先,我使用这里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)
    {

    }
}

如果我的 aFoo和 aDerivedFoo每个属性的值都相同,那么它们将具有相同的哈希码。这意味着我可以在 Linq 中拥有HashSet<Foo>或使用该Distinct方法,并且这两个实例将被视为相同。

我可能只是误解了使用,GetHashCode但我希望这两个实例具有不同的哈希码。这是一个无效的期望还是应该GetHashCode在计算中使用该类型?(或者DerivedClass也应该覆盖GetHashCode)?

PS我意识到有很多关于这个主题的问题,但我还没有发现直接回答这个问题的问题。

4

2 回答 2

6

GetHashCode()不应该保证唯一性(尽管如果尽可能独特,它有助于提高性能)。

的主要规则GetHashCode()是等效对象必须具有相同的哈希码,但这并不意味着非等效对象不能具有相同的哈希码。

如果两个对象具有相同的哈希码,Equals()则调用该方法以查看它们是否相同。由于类型不同(当然取决于您对 Equals 重载的编码方式),因此它们将不相等,因此会很好。

即使对每种类型都有不同的哈希码算法,仍然有可能发生冲突,因此也需要进行Equals()检查。

现在给出上面的示例,您不实现Equals()这将使每个对象都不同,而不管哈希码如何,因为Equals()from的默认实现object是引用相等检查。

如果您还没有,请继续并覆盖Equals()您的每种类型(如果您喜欢,它们可以继承您的实现GetHashCode(),或者有新的实现)并且您可以确保比较对象的类型是在宣布它们相等之前相同。并确保Equals()GetHashCode()始终实施,以便:

  • 对象Equals() 必须具有相同的GetHashCode()结果。
  • GetHashCode()不能不同的对象Equals()
于 2011-09-08T14:27:35.000 回答
1

这两个实例不需要具有不同的哈希码。HashSet 或其他框架类不会假定 GetHashCode 的结果,因为即使在一个类型内也可能存在冲突。GetHashCode 仅用于确定哈希表中存储项目的位置。如果 HashSet 中存在冲突,则它会依靠 Equals 方法的结果来确定唯一匹配。这意味着无论您实现 GetHashCode,您还应该实现 Equals(并检查类型是否匹配)。同样,无论何时实现 Equals,都应该实现 GetHashCode。在这里查看 Eric Lippert 的一个很好的解释。

于 2011-09-08T14:28:46.077 回答