给定像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?)只能使用五个值,但是其中两个(null和Season.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<>其结构是相关的,虽然)。无参数的用户编写的实现GetHashCode(),其中,其哈希码我们所追求的目标是永远不能处理的情况null。
这是关于实现抽象方法EqualityComparer<T>.GetHashCode(T)或以其他方式实现接口方法IEqualityComparer<T>.GetHashCode(T)。现在,当创建到MSDN的这些链接时,我看到它说如果这些方法ArgumentNullException的唯一参数为,则它们会抛出一个null。这肯定是MSDN上的错误吗?.NET自己的实现均未引发异常。在这种情况下抛出将有效地中断添加null到的任何尝试HashSet<>。除非HashSet<>在处理null项目时做一些特别的事情(我将不得不对此进行测试)。
新编辑/添加:
现在我尝试调试。使用HashSet<>,我可以确认使用默认的相等比较器,这些值Season.Spring和null 将在同一存储桶中结束。这可以通过非常仔细地检查私有数组成员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<>,甚至无法更改的哈希值null。相反,一种解决方案是更改所有其他值的哈希,如下所示:
class NewerNullEnumEqComp<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 ? 1 + Default.GetHashCode(x) : /* not seen by HashSet: */ 0;
  }
}