为什么在调用 GetHashCode() 时具有相同元素 return 个不同值的 HashSet?

Why HashSets with same elements return different values when calling to GetHashCode()?

为什么 HashSet<T>.GetHashCode() returns 具有相同元素的哈希码不同?

例如:

[Fact]
public void EqualSetsHaveSameHashCodes()
{
    var set1 = new HashSet<int>(new [] { 1, 2, 3 } );
    var set2 = new HashSet<int>(new [] { 1, 2, 3 } );

    Assert.Equal(set1.GetHashCode(), set2.GetHashCode());
}

此测试失败。为什么?

我怎样才能得到我需要的结果? "Equal sets give the same hashcode"

您可以实现自定义 HashSet 来覆盖 GetHashCode 函数,该函数从所有内容生成新的哈希码,如下所示:

public class HashSetWithGetHashCode<T> : HashSet<T>
{
    public override int GetHashCode()
    {
        unchecked // Overflow is fine, just wrap
        {
            int hash = 17;
            foreach (var item in this)
                hash = hash * 23 + item.GetHashCode();
            return hash;
        }
    }
}

默认情况下(除非另有特别说明),引用类型只有在引用同一对象时才被视为相等。作为开发人员,您可以覆盖 Equals() 和 GetHashCode() 方法,以便您认为相等的对象 return 对于 Equals 为真,对于 GetHashCode 为相同的 int。

根据您使用的测试框架,将有 CollectionAssert.AreEquivalent() 或对 Assert.Equal 的覆盖,它需要一个比较器。

HashSet<T> 默认情况下没有值相等语义。它具有引用相等语义,因此即使包含的元素相同,两个不同的哈希集也不会相等或具有相同的哈希码。

您需要使用特殊用途 IEqualityComparer<HashSet<int>> 才能获得您想要的行为。您可以自己滚动或使用框架为您提供的默认值:

var hashSetOfIntComparer = HashSet<int>.CreateSetComparer();

//will evaluate to true
var haveSameHash = hashSetOfIntComparer.GetHashCode(set1) ==
                   hashSetOfIntComparer.GetHashCode(set2);

所以,长话短说:

How can I get the result I need? "Equal sets give the same hashcode"

如果您打算使用 HashSet<T>.GetHashCode() 的默认实现,则不能。您要么使用特殊用途的比较器,要么扩展 HashSet<T> 并覆盖 EqualsGetHashCode 以满足您的需要。