鉴于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<>
结构,但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<>
,我可以确认使用默认的相等比较器,值null
和HashSet<>
will以相同的桶结尾。这可以通过非常仔细地检查私有数组成员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<>
鉴于像System.Collections.Generic.HashSet <>这样的集合接受null作为集合成员,人们可以问null的哈希码应该是什么。看起来框架使用0://可为空...
只要类型返回的哈希码为consistent
如果两个对象的哈希码不相等,则将它们视为不相等(因为我们假设不拘束的实现是正确的-即我们不会对此进行二次猜测)。如果它们具有相同的哈希码,则应检查它们的[[actual
have
为零