2012-09-26 32 views
0

我读到this question here,这导致我this article here我可以实现一个基本的GetHashCode(),它可以用于我的抽象基类的所有扩展?

我有一个抽象的基类,允许我限制方法只接受我的类扩展我的抽象基类(基本多态性)。我的问题是:我可以在抽象基类中实现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

好像它会很慢涉及反射散列 –

+0

接下来,我去了并做了一些关于GetHashCode()和Equals()及其相互关系的实现和使用的更多阅读。在获得更好的理解之后,我放弃了上面正在处理的基础GetHashCode()。排队其中一个旧的NBC PSA:更多你知道...... – JMD

+0

重写'structs'中的'GetHashCode()'总是好的原因之一就是避免使用与此相同的一般思想的默认值。它大部分时间都在使用,但是它比大多数简单的'GetHashCode()'重写要慢很多,你可以在一分钟之内编写代码。 –

回答

2

这是否有更好的表现比:

public override int GetHashCode() 
{ 
    return 1; 
} 

一键散列函数是它必须快速地计算。通过反思,你可能会失去从散列获得的所有好处。

这将是值得的基准。

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

编辑以添加: 另外,考虑在属性循环周围添加unchecked以防止发生异常,如果散列值大于Int.MaxValue。

+0

+1尤其是“哈希码匹配等于”的评论。请注意,由于反射不会使GetHashCode变慢,因为如果不对对象进行任何更改,结果可以被缓存。问题在于确保对象在调用之间不会发生变化。 –

+0

感谢对性能的惩罚和关于'unchecked'的说明。在我的情况下,我不会处理足够的对象(可能是几千个实例),以使性能受到明显影响。不过,我要回去重新考虑我前进的方向。 – JMD

0

使用反射比较慢,但在某些情况下它是可以接受的。当类的实例是散列表或字典中的键时,将使用GetHashCode函数。在大多数情况下,你知道什么时候需要它。有一些工具,如Resharperexample)可以为您生成GetHashCode和Equals函数,而不是手动编写它们。

+0

“在大多数情况下,你知道什么时候需要它。”哈!我也这么想!现在我发现,当我使用DevExpress XtraGrid(一个类似网格的控件)并将其绑定到我的对象的List <>时,DevExpress内部有时会使用我的对象作为键创建一个Hashtable。然后它崩溃。呸! – RenniePet

1

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

+2

-1 - 这是不正确的。如果您查看http://msdn.microsoft.com/en-us/library/system.object.gethashcode。aspx它明确地说“只要*有*没有修改对象状态,就必须始终返回相同的哈希码” –

+1

Eric Lippert写道:“规则:GetHashCode返回的整数不能在对象包含在数据中时更改结构依赖于哈希码保持稳定“。他还写道,指导方针是结果永远不会改变。对于他的完整解释,请阅读原文:http://blogs.msdn.com/b/ericlippert/archive/2011/02/28/guidelines-and-rules-for-gethashcode.aspx –

+0

这是不可能的如果哈希是从对象的状态派生的,则GetHashCode()的结果在对象的整个生命周期内保持不变。该规则会使每个使用对象状态生成散列码的示例失效。按照规则,从构建开始的那一刻起,您将不允许更改派生哈希码的任何值。 – JMD

相关问题