覆盖GetHashCode()

Pac*_*ane 20 c# resharper hash gethashcode

本文中,Jon Skeet提到他通常使用这种算法来覆盖GetHashCode().

public override int GetHashCode()
{
  unchecked // Overflow is fine, just wrap
  {
    int hash = 17;
    // Suitable nullity checks etc, of course :)
    hash = hash * 23 + Id.GetHashCode();
    return hash;
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,我尝试使用它,但Resharper告诉我,方法GetHashCode()应该只使用只读字段进行散列(尽管编译很好).什么是好的做法,因为现在我真的不能让我的字段是只读的?

我尝试通过Resharper生成这个方法,这是结果.

public override int GetHashCode()
{
  return base.GetHashCode();
}
Run Code Online (Sandbox Code Playgroud)

这没什么贡献,说实话......

Har*_*wok 17

如果您的所有字段都是可变的并且您必须实现GetHashCode方法,那么恐怕这是您需要的实现.

public override int GetHashCode() 
{ 
    return 1; 
} 
Run Code Online (Sandbox Code Playgroud)

是的,这是低效的,但这至少是正确的.

问题是GetHashCodeDictionary和HashSet集合正在使用它来将每个项目放在存储桶中.如果基于某些可变字段计算哈希码,并且在将对象放入HashSet或Dictionary后实际更改了字段,则无法再从HashSet或Dictionary中找到该对象.

请注意,对于返回相同HashCode 1的所有对象,这基本上意味着所有对象都放在HashSet或Dictionary中的同一个桶中.因此,HashSet或Dictionary中始终只有一个存储桶.尝试查找对象时,它将对唯一存储桶中的每个对象执行相等检查.这就像在链表中进行搜索一样.

有人可能会争辩说,如果我们可以确保在将对象添加到HashCode或Dictionary集合后永远不会更改字段,那么基于可变字段实现哈希码就可以了.我个人认为这很容易出错.两年后有人接管你的代码可能不会意识到这一点并且意外地破坏了代码.


Dmi*_*kiy 5

请注意,您的GetHashCode必须与您的Equals方法齐头并进.如果你可以只使用引用相等(当你的类中没有两个不同的实例可以相等时),那么你可以安全地使用继承自Object的Equals和GetHashCode.这比简单地return 1从GetHashCode 更好.