简化C#中重写Equals()、GetHashCode()以获得更好的可维护性
本文关键字:更好 可维护性 重写 Equals 简化 GetHashCode | 更新日期: 2023-09-27 18:27:52
我发现自己经常重写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 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;
}
我的问题
- 实施模式是否合理
- 考虑到贡献成分的价值分布良好,^是否足够?如果集合元素的哈希分布良好,那么在组合集合元素时,我是否需要乘以31到N
- 这段代码似乎可以抽象为使用反射来确定公共属性的代码,构建一个与手工编码的解决方案匹配的表达式树,并根据需要执行表达式树。这种做法看起来合理吗?某个地方是否有现有的实现
MSDN实际上并没有说"不要为可变类型重载Equals等人"。它以前这么说,但现在说:
当你定义一个类或结构时,你决定它是否有意义为创建值相等(或等价)的自定义定义类型。通常,当类型应添加到某种类型的集合中,或者在它们的主要用途是存储一组字段或属性。
http://msdn.microsoft.com/en-us/library/dd183755.aspx
尽管如此,当对象参与散列集合(Dictionary<T,U>
、HashSet<T>
等)时,散列代码的稳定性仍然很复杂
我决定选择两全其美,如下所述:
https://stackoverflow.com/a/9752155/141172
我发现自己经常重写Equals()和GetHashCode()
- MSDN说:不要为可变类型重载Equals等人
考虑到贡献成分的价值分布良好,^是否足够?
- 是的,但它们并不总是分布得很好。考虑
int
属性。建议用一些(小)素数移位
也许我在这里感到困惑,但null
上的检查是否应该在GetHashCode
覆盖中返回1而不是0?
所以
MyStringProp == null ? 0 : MyStringProp.GetHashValue()
应该是
MyStringProp == null ? 1 : MyStringProp.GetHashValue()