7

的实现Nullable<T>.GetHashCode()如下:

public override int GetHashCode()
{
    if (!this.HasValue)
    {
        return 0;
    }
    return this.value.GetHashCode();
}

然而,如果基础值也生成 0 的哈希码(例如,设置为 false 的 bool 或设置为 0 的 int32),那么我们有两个常见的具有相同哈希码的不同对象状态。在我看来,更好的实现应该是这样的。

public override int GetHashCode()
{
    if (!this.HasValue)
    {
        return 0xD523648A; // E.g. some arbitrary 32 bit int with a good mix of set and 
                           // unset bits (also probably a prime number).
    }
    return this.value.GetHashCode();
}
4

4 回答 4

4

是的,你说得有道理。如果您事先知道要存储哪些数据,则始终可以编写更好的 GetHashCode() 实现。这不是图书馆作家曾经拥有的奢侈品。但是,是的,如果你有很多布尔值?要么是 false 要么 !HasValue 那么默认实现会受到伤害。枚举和整数也一样,零是一个常见的值。

但是,您的论点是学术性的,更改实施成本减去一万分,您不能自己做。最好的办法是提交建议,正确的渠道是用户语音网站。在这方面获得牵引力将是困难的,祝你好运。

于 2012-11-23T12:19:39.710 回答
2

我们首先要注意,这个问题只是关于性能。为了正确性,哈希码不需要是唯一的或抗冲突的。虽然它对性能很有帮助。

实际上,这是哈希表的主要价值主张:实际上均匀分布的哈希码导致 O(1) 行为。

那么,什么哈希码常数最有可能在实际应用中产生最佳性能配置文件?

当然不是0因为0是常见的哈希码:0.GetHashCode() == 0. 这也适用于其他类型。0最差的候选人,因为它往往会经常发生。

那么如何避免碰撞呢?我的建议:

static readonly int nullableDefaultHashCode = GetRandomInt32();
public override int GetHashCode()
{
    if (!this.HasValue)
        return nullableDefaultHashCode;
    else
        return this.value.GetHashCode();
}

均匀分布,不太可能发生冲突,并且没有选择任意常数的风格问题。

请注意,这GetRandomInt32 可以实现为return 0xD523648A;. 它仍然比return 0;. 但最好查询廉价的伪随机数来源。

于 2012-11-23T11:45:32.017 回答
1

最后,Nullable<T>没有值的 a 必须返回一个哈希码,并且该哈希码应该是一个常量。

返回一个任意常量可能看起来更安全或更合适,在特定情况下查看时可能更安全Nullable<int>,但最终它只是:一个哈希。

在可以覆盖的整个集合中Nullable<T>(无限),零并不是比任何其他值更好的哈希码。

于 2012-11-23T11:40:47.133 回答
0

我不明白这里的担忧 - 在什么情况下表现不佳?

为什么你会认为散列函数基于一个值的结果很差。

我可以看到,如果 Type 的许多不同值散列到相同的结果,那将是一个问题。但是 null 哈希值与 0 相同的事实似乎微不足道。

据我所知,.NET 哈希函数最常见的用途是用于 Hashtable、HashSet 或 Dictionary 键,而零和 null 恰好在同一个存储桶中这一事实对整体性能影响不大。

于 2012-11-23T12:17:22.503 回答