应该在.NET中null的哈希码始终为零

问题描述 投票:87回答:9

鉴于System.Collections.Generic.HashSet<>之类的集合接受null作为集合成员,因此可以询问null的哈希码应该是什么。看起来框架使用0

// nullable struct type
int? i = null;
i.GetHashCode();  // gives 0
EqualityComparer<int?>.Default.GetHashCode(i);  // gives 0

// class type
CultureInfo c = null;
EqualityComparer<CultureInfo>.Default.GetHashCode(c);  // gives 0

这对于可为空的枚举可能会(有一点)问题。如果我们定义

enum Season
{
  Spring,
  Summer,
  Autumn,
  Winter,
}

然后Nullable<Season>(也称为Season?)只能采用五个值,但是其中两个,即nullSeason.Spring,具有相同的哈希码。

编写这样的“更好的”平等比较器很诱人:

class NewNullEnumEqComp<T> : EqualityComparer<T?> where T : struct
{
  public override bool Equals(T? x, T? y)
  {
    return Default.Equals(x, y);
  }
  public override int GetHashCode(T? x)
  {
    return x.HasValue ? Default.GetHashCode(x) : -1;
  }
}

但是为什么null的哈希码应为0

编辑/添加:

[有些人似乎认为这是覆盖Object.GetHashCode()。实际上,实际上并非如此。 (但是.NET的作者确实在GetHashCode()结构中重写了Nullable<>结构,但is却没有覆盖。)用户编写的无参数GetHashCode()实现永远无法处理对象的情况。我们寻求其哈希码为null

这是关于实现抽象方法EqualityComparer<T>.GetHashCode(T)或以其他方式实现接口方法EqualityComparer<T>.GetHashCode(T)。现在,在创建到MSDN的这些链接时,我看到它说如果这些方法的唯一参数是IEqualityComparer<T>.GetHashCode(T),则它们将抛出IEqualityComparer<T>.GetHashCode(T)。这肯定是MSDN上的错误吗? .NET自己的实现均未引发异常。在这种情况下抛出将有效地中断将ArgumentNullException添加到null的任何尝试。除非null在处理HashSet<>项目时做得特别出色(我将不得不对其进行测试)。

新编辑/添加:

现在我尝试调试。使用HashSet<>,我可以确认使用默认的相等比较器,值nullHashSet<> will以相同的桶结尾。这可以通过非常仔细地检查私有数组成员Season.Springnull来确定。请注意,根据设计,索引总是偏移一个。

但是,我在上面提供的代码无法解决此问题。事实证明,当值是m_buckets时,m_slots甚至不会询问相等比较器。这来自HashSet<>的源代码:

null

这意味着,至少对于HashSet<>,甚至不可能更改 // Workaround Comparers that throw ArgumentNullException for GetHashCode(null). private int InternalGetHashCode(T item) { if (item == null) { return 0; } return m_comparer.GetHashCode(item) & Lower31BitMask; } 的哈希。相反,一种解决方案是更改所有其他值的哈希,如下所示:] >

HashSet<>    

鉴于像System.Collections.Generic.HashSet <>这样的集合接受null作为集合成员,人们可以问null的哈希码应该是什么。看起来框架使用0://可为空...

c# .net hash null
9个回答
24
投票

只要类型返回的哈希码为consistent


6
投票
[请记住,哈希码仅用作确定相等性的第一步,并且[永远不应该]事实上不用于确定两个对象是否相等。

如果两个对象的哈希码不相等,则将它们视为不相等(因为我们假设不拘束的实现是正确的-即我们不会对此进行二次猜测)。如果它们具有相同的哈希码,则应检查它们的[[actual


5
投票
不是

have

为零

4
投票
我刚刚尝试编写此代码:

4
投票

2
投票
必须

1
投票

1
投票
© www.soinside.com 2019 - 2024. All rights reserved.