基本上,到目前为止,我有以下内容:
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
。这是一个坏主意,如果是这样,我该怎么做呢?
答案 0 :(得分:7)
一个非常简单的hash code method for custom classes是对每个字段的哈希码进行按位异或。它可以这么简单:
int hash = 0;
hash ^= this.Title.GetHashCode();
hash ^= this.PublishDate.GetHashCode();
hash ^= this.Description.GetHashCode();
return hash;
来自link above:
XOR具有以下不错的属性:
- 它不依赖于计算顺序。
- 它不会“浪费”比特。如果您在其中一个组件中更改了一位,则最终值将会更改。
- 即便是最原始的计算机,它也很快,一个循环。
- 保持均匀分布。如果你组合的两个部分是均匀分布的,那么组合就是这样。换句话说,它不会将摘要的范围缩小到更窄的范围。
如果您希望在字段中具有重复值,则XOR不能正常工作,因为重复值会在XORed时相互抵消。因为你在一起散列三个不相关的字段,在这种情况下不应该是一个问题。
答案 1 :(得分:5)
我认为您选择使用的方法不存在问题。担心“太多”哈希冲突几乎总是表明过度思考问题;只要散列很可能不同,你应该没问题。
最终,如果可以合理地预期大部分时间对象可以根据其标题和出版日期(书籍?)进行区分,您甚至可能会考虑从您的哈希中省略Description
。< / p>
你甚至可以考虑完全忽略你的哈希函数中的GUID,并且只在Equals
实现中使用它来消除不太可能的(?)哈希冲突的情况。