我正在尝试覆盖GetHashCode
以确保唯一性,因为我将实例用作字典中的键:
IDictionary<Base, int> _counts = new Dictionary<Base,int>();
我遇到的两个课程是:
class sealed First : Base
{
public MyEnum1 value;
public ExtrasEnum extras;
public override int GetHashCode()
{
unchecked
{
return ((int)value* 397) ^ (int)extras;
}
}
//Other stuff
}
class sealed Second : Base
{
public MyEnum2 value;
public ExtrasEnum extras;
public override int GetHashCode()
{
unchecked
{
return ((int)value* 397) ^ (int)extras;
}
}
//Other stuff
}
然而。问题是当value
和extras
int值相同时,哈希码将相等。
计算是Resharper的推荐计算。
我如何确保theese类的哈希码不一样?
只是将它与另一个素数混合起来,或者?
修改
只是解释一下。我需要,如果First
的实例具有相同的value
和extras
值,则必须将这两个实例视为相同,但如果是First
的实例,则Second
的实例具有相同的value
和extras
的int值,因此不能将它们视为相同。
我不是在考虑性能,而只是为了确保相同的类实例是相同的,并且不同的类实例是不同的。
答案 0 :(得分:3)
从 enum 成员生成完美哈希并不是很困难。假设他们不会超过256个成员,你可以写一个快速的成员:
public override int GetHashCode() {
return ((int)value << 8) ^ (int)extras;
}
通过将Second.GetHashCode()写为:
,根本不会产生任何冲突public override int GetHashCode() {
return ((int)value << 16) ^ (int)extras;
}
非常简单和完美,但当您添加更多派生类时,当然不会扩展。它真的不需要,你是微观优化而没有任何洞察真正如何加速你的代码。请记住,完美的哈希不能避免字典中的桶冲突,桶索引是通过使用素数的哈希码的模来计算的。字典中的项目数越多,素数就越大。
根本就不要这样做。如果您想了解是否需要,请始终使用分析器。
答案 1 :(得分:2)
我认为您认为哈希码不得碰撞。一般来说,这显然是不可能确保的。 GetHashCode
的以下实施始终有效:return 0;
。 (这只是缓慢但不正确。)
这样做的方法是保持你的哈希码计算(因为它很好),但也要覆盖Equals
。在那里你可以区分这两种类型。例如,说:
if (a.GetType() != b.GetType()) return false;
如果我误解了你的问题,你的问题的字面答案就是考虑到班级的类型:
oldHashCode ^ this.GetType().GetHashCode();
(这也不能确保唯一性。)