在 C# 中实现 GetHashCode。空值处理

And*_*ren 5 .net c# hash

在开始之前,我在 Mono 环境中测试了这里的所有代码示例,并且在GetHashCode实现上有一个明显的区别:

string.Empty.GetHashCode(); // returns 0 in Mono 3.10
string.Empty.GetHashCode(); // returns 757602046 in .NET 4.5.1
Run Code Online (Sandbox Code Playgroud)

我根据@JonSkeet 的这个SO Answer进行了我的实现,并且在评论中他还建议对 NULL 值使用 0 哈希码(不确定我应该如何对它们进行哈希处理)。

我通常使用 0 作为 null 的有效哈希码 - 这与忽略该字段不同。

所以有以下实现(Mono 3.10):

public class Entity {
    public int EntityID { get; set; }
    public string EntityName { get; set; }

    public override int GetHashCode() {
        unchecked {
            int hash = 15485863;       // prime number
            int multiplier = 1299709;  // another prime number

            hash = hash * multiplier + EntityID.GetHashCode();
            hash = hash * multiplier + (EntityName != null ? EntityName.GetHashCode() : 0);

            return hash;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

很容易找到碰撞,例如

var hash1 = new Entity { EntityID = 1337, EntityName = "" }.GetHashCode();
var hash2 = new Entity { EntityID = 1337, EntityName = null }.GetHashCode();

bool equals = hash1 == hash2; // true
Run Code Online (Sandbox Code Playgroud)

我可以用其他一些数字替换空值 0,但是它不会解决问题,因为某些哈希(字符串)输出仍然有可能生成这样的数字,我会再次发生冲突。

我的问题:在使用上面示例中的算法时,我应该如何处理空值?

Nit*_*ram 4

这里的“问题”是您正在尝试获取无冲突的哈希码。虽然这对于使用哈希码进行查找(例如HashSetDictionary)的集合实现的查找性能来说是完美的,但在大多数情况下这是行不通的。

原因是哈希码只是一个 32 位整数值,它代表的数据通常要大得多(多个整数值、字符串等)。

因此,哈希码仅用于定义两个对象是否相等。集合类使用哈希码来细化对象存储的区域,并使用 equals 函数来查找两个对象是否确实相同。因此,您应该始终Equals为您实现了哈希码的类实现该函数。虽然这些类将回退到对象的 equals 函数,但实现该IEquatable<T>接口以避免任何类型的键入问题也是一个好主意吗(仍然覆盖对象的默认 equals 方法!)