简化重载的equals(),在C#的GetHashCode()为更好的可维护性 [英] Simplify Overriding Equals(), GetHashCode() in C# for Better Maintainability

查看:121
本文介绍了简化重载的equals(),在C#的GetHashCode()为更好的可维护性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现我自己重写等于()的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;
}

我的问题




  1. 是实现模式的声音?

  2. 是^充分考虑到有助于元件值均匀分布?我需要31到该-N结合收集要素赋予它们的散列分布均匀?何时乘

  3. 看来这个代码可以抽象成使用反射来确定公共代码性质,构建一个手工编码的溶液相匹配的表达式树,并根据需要执行表达式树。请问这种做法似乎是合理的?有一个现有实现的地方?


解决方案

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() and GetHashCode() 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

  1. Is the implementation pattern sound?
  2. 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?
  3. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆