在这篇文章中,Jon提到他通常使用这种算法来重写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;
}
}现在,我尝试使用这个方法,但是Resharper告诉我,方法GetHashCode()应该只使用只读字段进行散列(尽管它编译得很好)。什么是一个很好的练习,因为现在我真的不能把我的字段变成只读的?
我尝试用Resharper生成这个方法,结果如下。
public override int GetHashCode()
{
return base.GetHashCode();
}老实说,这没什么用.
发布于 2012-07-14 06:18:31
如果所有字段都是可变的,并且必须实现GetHashCode方法,那么恐怕这就是您需要的实现。
public override int GetHashCode()
{
return 1;
} 是的,这是低效的,但这至少是正确的。
问题是,字典和GetHashCode集合正在使用HashSet将每一项放在一个桶中。如果哈希代码是基于一些可变字段计算的,并且在将对象放入HashSet或Dictionary之后,这些字段确实发生了更改,则不能再从HashSet或Dictionary中找到该对象。
注意,由于所有对象返回相同的HashCode 1,这基本上意味着所有对象都放在HashSet或字典中的同一个桶中。因此,“HashSet”或“字典”中总是只有一个桶。当试图查找对象时,它将对唯一桶内的每个对象执行相等检查。这就像在链接列表中搜索一样。
有人可能会说,如果我们能够确保在添加到hashcode或Dictionary集合中的对象之后不会更改字段,那么实现基于可变字段的哈希代码可能会很好。我个人的看法是,这是容易出错的。两年后接管您的代码的人可能不会意识到这一点,并意外地破坏了代码。
发布于 2012-07-14 15:39:22
请注意,您的GetHashCode必须与您的相等方法并驾齐驱。如果您只需要使用引用相等(当您从来没有两个可以相等的类的不同实例时),那么您就可以安全地使用从对象继承的相等和GetHashCode。这将比简单地使用return 1 (来自GetHashCode )要好得多。
发布于 2013-10-29 09:54:53
我个人倾向于在没有不可变字段的类中,为GetHashCode()的每个实现返回一个不同的数值。这意味着,如果我有一个包含不同实现类型的字典,就有可能将不同类型的不同实例放入不同的桶中。
例如
public class A
{
// TODO Equals override
public override int GetHashCode()
{
return 21313;
}
}
public class B
{
// TODO Equals override
public override int GetHashCode()
{
return 35507;
}
}然后,如果我有一个包含Dictionary<object, TValue>实例的A、B和其他类型的实例,那么查找的性能将比所有GetHashCode的实现返回相同的数值要好。
还应该注意的是,我利用素数得到了更好的分布。
根据注释,我提供了一个LINQPad示例这里,它演示了对不同类型使用return 1与为每种类型返回不同值之间的性能差异。
https://stackoverflow.com/questions/11481323
复制相似问题