我发现自己经常覆盖 Equals()
和 GetHashCode()
方法,以实现具有相同属性值的业务对象相等的语义。这会导致编写重复且难以维护的代码(如果添加属性,则一个或两个方法都未更新)。
最终代码看起来像这样(欢迎对实现进行评论):
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 https://dev59.com/jHVD5IYBdhLWcg3wNY1Z#9658866
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;
}
我的问题
- 这个实现模式是否正确?
- 如果贡献部件的值分布良好,那么是否^足够?在组合集合元素时,是否需要乘以31的N次方,给定它们的哈希是分布均匀的?
- 看起来这段代码可以抽象出使用反射确定公共属性、构建与手写解决方案匹配的表达式树,并根据需要执行表达式树的代码。这种方法是否合理?是否已经有现成实现?