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

时间:2018-11-25 21:44:35

标签: c# .net set hashcode

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

例如:

[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());
}

此测试失败。为什么?

如何获得所需的结果? “相等的集合给出相同的哈希码”

3 个答案:

答案 0 :(得分:2)

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

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

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

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

因此,总而言之:

  

如何获得所需的结果? “相等的集合给出相同的哈希码”

如果计划使用HashSet<T>.GetHashCode()的默认实现,则不能。您可以使用专用比较器,也可以扩展HashSet<T>并覆盖EqualsGetHashCode以适合您的需求。

答案 1 :(得分:1)

默认情况下(除非另有明确说明,否则)引用类型仅在引用同一对象时才被视为相等。作为开发人员,您可以重写Equals()和GetHashCode()方法,以使您认为相等的对象对Equals返回true,对GetHashCode返回相同的int。

根据要使用的测试框架,将使用CollectionAssert.AreEquivalent()或使用比较器的Assert.Equal的替代。

答案 2 :(得分:-1)

您可以实现一个自定义的HashSet,该自定义的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;
        }
    }
}