编辑: System.HashCode
现已发布。现在推荐的创建哈希码的方法是:
public override int GetHashCode()
{
return HashCode.Combine(fieldA, fieldB, fieldC);
}
System.HashCode.Combine()
将在内部调用.GetHashCode()
每个字段,并自动执行正确的操作。
对于非常多的字段(超过 8 个),您可以创建一个实例,HashCode
然后使用该.Add()
方法:
public override int GetHashCode()
{
HashCode hash = new HashCode();
hash.Add(fieldA);
hash.Add(fieldB);
hash.Add(fieldC);
hash.Add(fieldD);
hash.Add(fieldE);
hash.Add(fieldF);
hash.Add(fieldG);
hash.Add(fieldH);
hash.Add(fieldI);
return hash.ToHashCode();
}
Equals()
Visual Studio 2019 现在有一个可以为您生成的快速操作帮助程序GetHashCode()
。只需右键单击声明中的类名 > Quick Actions and Refactorings > Generate Equals 和 GetHashCode。选择您希望它用于相等的成员,以及“实现 IEquatable”,然后单击“确定”。
最后一件事:如果您需要获取对象的结构哈希码,例如,如果您想包含根据其内容(也称为结构)而不是其引用而更改的数组的哈希码,那么您将需要强制转换字段IStructuralEquatable
并手动获取其哈希码,如下所示:
public override int GetHashCode()
{
return HashCode.Combine(
fieldA,
((IStructuralEquatable)stringArrayFieldB).GetHashCode(EqualityComparer<string>.Default));
}
这是因为IStructuralEquatable
接口几乎总是显式实现,因此IStructuralEquatable
需要强制转换为调用IStructuralEquatable.GetHashCode()
而不是默认object.GetHashCode()
方法。
最后,在当前实现.GetHashCode
中 anint
只是整数值本身,因此传入哈希码值HashCode.Combine()
而不是字段本身对结果没有影响。
老答案:
为了完整起见,这里是从.NET 元组参考源第 52 行获取的散列算法。有趣的是,这个散列算法是从 .NET 复制过来的System.Web.Util.HashCodeCombiner
。
这是代码:
public override int GetHashCode() {
// hashing method taken from .NET Tuple reference
// expand this out to however many items you need to hash
return CombineHashCodes(this.item1.GetHashCode(), this.item2.GetHashCode(), this.item3.GetHashCode());
}
internal static int CombineHashCodes(int h1, int h2) {
// this is where the magic happens
return (((h1 << 5) + h1) ^ h2);
}
internal static int CombineHashCodes(int h1, int h2, int h3) {
return CombineHashCodes(CombineHashCodes(h1, h2), h3);
}
internal static int CombineHashCodes(int h1, int h2, int h3, int h4) {
return CombineHashCodes(CombineHashCodes(h1, h2), CombineHashCodes(h3, h4));
}
internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5) {
return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), h5);
}
internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6) {
return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), CombineHashCodes(h5, h6));
}
internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6, int h7) {
return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), CombineHashCodes(h5, h6, h7));
}
internal static int CombineHashCodes(int h1, int h2, int h3, int h4, int h5, int h6, int h7, int h8) {
return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), CombineHashCodes(h5, h6, h7, h8));
}
当然,实际的元组GetHashCode()
(实际上是一个Int32 IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
)有一个很大的switch
块来决定根据它持有的项目数量来调用其中的哪一个——您自己的代码可能不需要这样做。