为什么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());
}
此测试失败。为什么?
如何获得所需的结果? “相等的集合给出相同的哈希码”
答案 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>
并覆盖Equals
和GetHashCode
以适合您的需求。
答案 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;
}
}
}