0

我在这里阅读了这个问题,这使我在这里找到了这篇文章

我有一个抽象基类,它允许我限制方法只接受扩展我的抽象基类(基本多态性)的类。我的问题是:我可以GetHashCode()在我的抽象基类中实现为任何具体实现提供合适的覆盖吗?(即避免GetHashCode()在每个具体类中覆盖。)

我在我的抽象基类中想象一个方法是这样的:

public abstract class FooBase
{
    private static readonly int prime_seed = 13;
    private static readonly int prime_factor = 7;

    public override int GetHashCode()
    {
        // Seed using the hashcode for this concrete class' Type so
        // two classes with the same properties return different hashes.
        int hash = prime_seed * this.GetType().GetHashCode();
        // Get this concrete class' public properties.
        var props = this.GetType().GetProperties(BindingFlags.Public);
        foreach (var prop in props)
        {
            // Factor in each of this concrete class' public properties' hashcodes.
            hash = (hash * prime_factor) + prop.GetHashCode();
        }
        return hash;
    }
}

这似乎适用于一些基本的平等单元测试,但我觉得我忽略了一些东西。我仍然必须在每个具体类中提供覆盖以避免编译器警告不要覆盖 GetHashCode(),但至少这样我不必为每个类手动编写实现。

4

3 回答 3

2

这是否比以下表现更好:

public override int GetHashCode()
{
    return 1;
}

哈希函数的一个关键是它必须快速计算。通过反射,您可能会失去从哈希中获得的所有好处。

进行基准测试是值得的。

此外,当 Equals 返回 true 时,哈希码必须相等,所以所有子类在其 Equals 方法中只使用公共属性吗?如果没有,您可能会考虑遍历所有属性,而不仅仅是公共属性。

编辑添加:此外,考虑在您的属性循环周围添加未经检查的内容,以防止在哈希大于 Int.MaxValue 时出现异常。

于 2012-09-26T19:25:30.680 回答
1

您错过了一条基本规则 - GetHashCode() 结果必须在对象的整个生命周期内保持不变。在您的 GetHashCode 实现中,不能保证(因为您正在迭代的属性可能是可变的)。

于 2012-09-26T19:22:57.487 回答
0

使用反射相当慢,但在某些情况下它是可以接受的。当类的实例是哈希表或字典中的键时,使用 GetHashCode 函数。在大多数情况下,您知道何时需要它。有一些工具,例如Resharper ( example ),可以为您生成 GetHashCode 和 Equals 函数,而不是手动编写它们。

于 2012-09-26T19:18:32.333 回答