我应该如何实现 Object.GetHashCode() 以获得复杂的相等性?
-
21-08-2019 - |
题
基本上,到目前为止我有以下内容:
class Foo {
public override bool Equals(object obj)
{
Foo d = obj as Foo ;
if (d == null)
return false;
return this.Equals(d);
}
#region IEquatable<Foo> Members
public bool Equals(Foo other)
{
if (this.Guid != String.Empty && this.Guid == other.Guid)
return true;
else if (this.Guid != String.Empty || other.Guid != String.Empty)
return false;
if (this.Title == other.Title &&
this.PublishDate == other.PublishDate &&
this.Description == other.Description)
return true;
return false;
}
}
所以,问题是这样的:我有一个非必填字段 Guid
, ,这是一个唯一标识符。如果未设置,那么我需要尝试根据不太准确的指标来确定相等性,以尝试确定两个对象是否相等。这工作正常,但它使 GetHashCode()
凌乱的...我该怎么办?一个简单的实现是这样的:
public override int GetHashCode() {
if (this.Guid != String.Empty)
return this.Guid.GetHashCode();
int hash = 37;
hash = hash * 23 + this.Title.GetHashCode();
hash = hash * 23 + this.PublishDate.GetHashCode();
hash = hash * 23 + this.Description.GetHashCode();
return hash;
}
但这两种类型的哈希发生冲突的可能性有多大?当然,我没想到会是这样 1 in 2 ** 32
. 。这是一个坏主意吗?如果是的话,我应该怎么做?
解决方案
我不认为这是与您选择使用的方法有问题。令人担忧的“过多”有关哈希冲突几乎总是指示过思考的问题;只要散列极有可能是不同的,你应该罚款。
最后你甚至要考虑从您的哈希离开了Description
无论如何,如果它是合理的期望,大部分时间对象都可以根据自己的标题和发布日期尊贵(书吗?)。
您甚至可以考虑在你的哈希函数不顾GUID干脆,只有使用它在Equals
实施消除歧义哈希冲突的可能性不大(?)的情况下。
其他提示
一个非常简单的 自定义类的哈希码方法 是将每个字段的哈希码按位异或在一起。它可以像这样简单:
int hash = 0;
hash ^= this.Title.GetHashCode();
hash ^= this.PublishDate.GetHashCode();
hash ^= this.Description.GetHashCode();
return hash;
来自 上面的链接:
XOR 具有以下优良特性:
- 它不依赖于计算顺序。
- 它不会“浪费”比特。如果更改其中一个组件中的哪怕一位,最终值都会发生变化。
- 即使在最原始的计算机上,它也很快,只需一个周期。
- 它保持均匀分布。如果你组合的两块是均匀分布的,那么组合也会是均匀分布的。换句话说,它不会将摘要的范围压缩成更窄的范围。
如果您希望字段中存在重复值,则异或效果不佳,因为异或时重复值会相互抵消。由于您将三个不相关的字段散列在一起,因此在这种情况下应该不是问题。
不隶属于 StackOverflow