我读了this question here,这导致我this article here。
我有一个抽象基类,它允许我约束方法只接受扩展我的抽象基类(基本多态)的类。我的问题是:我可以在我的抽象基类中实现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(),但至少这样我不必为每个类手动编写实现。
答案 0 :(得分:2)
这是否比以下表现更好:
public override int GetHashCode()
{
return 1;
}
哈希函数的关键是计算速度必须快。通过反射,您可能会失去通过哈希获得的所有好处。
基准测试是值得的。
此外,当Equals返回true时,哈希码必须相等,那么所有子类在其Equals方法中是否只使用公共属性?如果没有,您可以考虑循环所有属性,而不仅仅是公共属性。
编辑添加: 另外,考虑在属性循环周围添加unchecked以防止异常(如果散列大于Int.MaxValue)。
答案 1 :(得分:1)
您错过了一个基本规则 - GetHashCode()结果必须在对象的整个生命周期内保持不变。在您的GetHashCode实现中,它不受保证(因为您正在迭代的属性可以是可变的)。
答案 2 :(得分:0)