简化重载的equals(),在C#的GetHashCode()为更好的可维护性 [英] Simplify Overriding Equals(), GetHashCode() in C# for Better Maintainability
问题描述
我发现我自己重写等于()
和的GetHashCode()
经常来实现语义与业务对象相同的属性值相等。这导致代码的重复编写和脆弱的维持(属性,都会增加一/不更新这两个覆盖的)。
代码尾部有像这样(的实施意见,欢迎):
公共覆盖布尔等于(obj对象)
{
如果(object.ReferenceEquals(这一点,OBJ))返回true;
MyDerived其他= OBJ时MyDerived;
如果(其他== NULL)返回false;
布尔baseEquals = base.Equals((MyBase)除外);
回报率(baseEquals&安培;&安培;
this.MyIntProp == other.MyIntProp&放大器;&安培;
this.MyStringProp == other.MyStringProp&放大器;&安培;
this.MyCollectionProp .IsEquivalentTo(other.MyCollectionProp)及&放大器; //参见http://stackoverflow.com/a/9658866/141172
this.MyContainedClass.Equals(other.MyContainedClass));
}
公共覆盖INT的GetHashCode()
{
INT hashOfMyCollectionProp = 0;
// http://computinglife.wordpress.com/2008/11/20/why-do-hash-functions-use-prime-numbers/
// ...但它是值得的鉴于elem.GetHashCode()应均匀分布额外的数学吗?
INT bitSpreader = 31;
的foreach(在MyCollectionProp VAR ELEM)
{
hashOfMyCollectionProp =吊具* elem.GetHashCode();
bitSpreader * = 31;
}
返回base.GetHashCode()^ ^ //是一个很好的组合如果组合值分布均匀
MyIntProp.GetHashCode()^
(MyStringProp == NULL? 0:MyStringProp.GetHashValue())^
(MyContainedClass == NULL?0:MyContainedClass.GetHashValue())^
hashOfMyCollectionProp;
}
我的问题
- 是实现模式的声音?
- 是^充分考虑到有助于元件值均匀分布?我需要31到该-N结合收集要素赋予它们的散列分布均匀?何时乘
- 看来这个代码可以抽象成使用反射来确定公共代码性质,构建一个手工编码的溶液相匹配的表达式树,并根据需要执行表达式树。请问这种做法似乎是合理的?有一个现有实现的地方?
MSDN实际的不说不超载等于为可变类型等。它曾经这么说,但现在它说:
当你定义一个类或结构,决定是否有意义
,来创造
类型的值相等(或等值)的自定义。通常情况下,实施的值相等,预计的
类型的对象时被添加到某种的集合,或当
它们的主要目的是存储一组字段或属性的
块引用>
http://msdn.microsoft.com/en-us/library/dd183755.aspx
不过,也有周围的哈希码而稳定的复杂性一个对象参与了散列集合(
词典< T,U>
,的HashSet< T>
等)。
我决定选择两全其美的,如下所示:
的http://stackoverflow.com/a/9752155/141172
I find my self overriding
Equals()
andGetHashCode()
frequently to implement the semantic that business objects with identical property values are equal. That leads to code that is repetitive to write and fragile to maintain (property gets added and one/both of the overrides are not updated).The code ends up looking something like this (comments on the implementation are welcome):
public override bool Equals(object obj) { if (object.ReferenceEquals(this, obj)) return true; MyDerived other = obj as MyDerived; if (other == null) return false; bool baseEquals = base.Equals((MyBase)other); return (baseEquals && this.MyIntProp == other.MyIntProp && this.MyStringProp == other.MyStringProp && this.MyCollectionProp.IsEquivalentTo(other.MyCollectionProp) && // See http://stackoverflow.com/a/9658866/141172 this.MyContainedClass.Equals(other.MyContainedClass)); } public override int GetHashCode() { int hashOfMyCollectionProp = 0; // http://computinglife.wordpress.com/2008/11/20/why-do-hash-functions-use-prime-numbers/ // BUT... is it worth the extra math given that elem.GetHashCode() should be well-distributed? int bitSpreader = 31; foreach (var elem in MyCollectionProp) { hashOfMyCollectionProp = spreader * elem.GetHashCode(); bitSpreader *= 31; } return base.GetHashCode() ^ // ^ is a good combiner IF the combined values are well distributed MyIntProp.GetHashCode() ^ (MyStringProp == null ? 0 : MyStringProp.GetHashValue()) ^ (MyContainedClass == null ? 0 : MyContainedClass.GetHashValue()) ^ hashOfMyCollectionProp; }
My Questions
- Is the implementation pattern sound?
- Is ^ adequate given that the contributing component values are well-distributed? Do I need to multiply by 31-to-the-N when combining collection elements given their hash is well distributed?
- It seems this code could be abstracted into code that uses reflection to determine public properties, builds an expression tree that matches the hand-coded solution, and executes the expression tree as needed. Does that approach seem reasonable? Is there an existing implementation somewhere?
解决方案MSDN actually doesn't say "don't overload Equals et al for mutable types". It used to say that, but now it says:
When you define a class or struct, you decide whether it makes sense to create a custom definition of value equality (or equivalence) for the type. Typically, you implement value equality when objects of the type are expected to be added to a collection of some sort, or when their primary purpose is to store a set of fields or properties.
http://msdn.microsoft.com/en-us/library/dd183755.aspx
Still, there are complexities surrounding stability of the hash code while an object participates in a hashed collection (
Dictionary<T,U>
,HashSet<T>
, etc.).I decided to opt for the best of both worlds, as outlined here:
http://stackoverflow.com/a/9752155/141172
这篇关于简化重载的equals(),在C#的GetHashCode()为更好的可维护性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!