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
}

不过。问题是当 valueextras int 值变得相同时,哈希码将相等。 该计算是 Resharper 推荐的计算。 我如何确保这些 classes 的哈希码不相同? 只需将它与另一个质数混合一下,或者?

编辑: 只是为了解释。我需要如果 First 的实例具有相同的 valueextras 值,那么这两个实例必须被认为是相同的,但是如果 First 的实例和Second 的实例具有与 valueextras 相同的 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; 
}

非常简单和完美,但是当您添加更多派生时当然不会扩展 类。确实不需要,您只是在进行微观优化,而没有深入了解 真正 如何加速您的代码。请记住,完美的哈希并不能避免字典中的桶冲突,桶索引是通过将哈希码与质数取模来计算的。字典中的项目数越多,素数越大。

根本就不要这样做。如果你想知道是否需要,请始终使用分析器。