GetHashCode计算
GetHashCode calculation
我正在尝试覆盖 GetHashCode
以确保唯一性,因为我将实例用作字典中的键:
IDictionary<Base, int> _counts = new Dictionary<Base,int>();
我遇到问题的两个 class 是:
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 推荐的计算。
我如何确保这些 classes 的哈希码不相同?
只需将它与另一个质数混合一下,或者?
编辑:
只是为了解释。我需要如果 First
的实例具有相同的 value
和 extras
值,那么这两个实例必须被认为是相同的,但是如果 First
的实例和Second
的实例具有与 value
和 extras
相同的 int 值,那么这些不能被认为是相同的。
我不是在研究性能,只是为了确保相同的 class 个实例是相等的,不同的 class 个实例是不同的。
我假设您认为哈希码不能冲突。这显然是一般情况下无法保证的。 GetHashCode
的以下实现始终有效:return 0;
。 (它只是慢但不是不正确。)
解决这个问题的方法是保留你的哈希码计算(因为它很好)但也覆盖 Equals
。在那里您可以区分这两种类型。例如说:
if (a.GetType() != b.GetType()) return false;
万一我误解了你的顾虑,对你问题的字面回答是考虑 class 的类型:
oldHashCode ^ this.GetType().GetHashCode();
(这也不能确保唯一性。)
从 enum 成员中生成一个完美的散列并不难。假设他们不会有超过 256 个成员,你可以写一个快速的:
public override int GetHashCode() {
return ((int)value << 8) ^ (int)extras;
}
并且通过将 Second.GetHashCode() 写为:
根本不会产生任何冲突
public override int GetHashCode() {
return ((int)value << 16) ^ (int)extras;
}
非常简单和完美,但是当您添加更多派生时当然不会扩展 类。确实不需要,您只是在进行微观优化,而没有深入了解 真正 如何加速您的代码。请记住,完美的哈希并不能避免字典中的桶冲突,桶索引是通过将哈希码与质数取模来计算的。字典中的项目数越多,素数越大。
根本就不要这样做。如果你想知道是否需要,请始终使用分析器。
我正在尝试覆盖 GetHashCode
以确保唯一性,因为我将实例用作字典中的键:
IDictionary<Base, int> _counts = new Dictionary<Base,int>();
我遇到问题的两个 class 是:
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 推荐的计算。
我如何确保这些 classes 的哈希码不相同?
只需将它与另一个质数混合一下,或者?
编辑:
只是为了解释。我需要如果 First
的实例具有相同的 value
和 extras
值,那么这两个实例必须被认为是相同的,但是如果 First
的实例和Second
的实例具有与 value
和 extras
相同的 int 值,那么这些不能被认为是相同的。
我不是在研究性能,只是为了确保相同的 class 个实例是相等的,不同的 class 个实例是不同的。
我假设您认为哈希码不能冲突。这显然是一般情况下无法保证的。 GetHashCode
的以下实现始终有效:return 0;
。 (它只是慢但不是不正确。)
解决这个问题的方法是保留你的哈希码计算(因为它很好)但也覆盖 Equals
。在那里您可以区分这两种类型。例如说:
if (a.GetType() != b.GetType()) return false;
万一我误解了你的顾虑,对你问题的字面回答是考虑 class 的类型:
oldHashCode ^ this.GetType().GetHashCode();
(这也不能确保唯一性。)
从 enum 成员中生成一个完美的散列并不难。假设他们不会有超过 256 个成员,你可以写一个快速的:
public override int GetHashCode() {
return ((int)value << 8) ^ (int)extras;
}
并且通过将 Second.GetHashCode() 写为:
根本不会产生任何冲突public override int GetHashCode() {
return ((int)value << 16) ^ (int)extras;
}
非常简单和完美,但是当您添加更多派生时当然不会扩展 类。确实不需要,您只是在进行微观优化,而没有深入了解 真正 如何加速您的代码。请记住,完美的哈希并不能避免字典中的桶冲突,桶索引是通过将哈希码与质数取模来计算的。字典中的项目数越多,素数越大。
根本就不要这样做。如果你想知道是否需要,请始终使用分析器。