GetHashCode应该取决于类型吗?

时间:2011-09-08 14:23:46

标签: c# inheritance gethashcode

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

    }
}

如果我为每个属性设置了FooDerivedFoo,则它们将具有相同的哈希码。这意味着我可以在Linq中使用HashSet<Foo>或使用Distinct方法,这两个实例将被视为相同。

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

P.S。我意识到关于这个主题的SO有很多很多问题,但是我没有发现直接回答这个问题的问题。

2 个答案:

答案 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的一个很好的解释。