9

私は自分自身をオーバーライドEquals()GetHashCode()、同一のプロパティ値を持つビジネス オブジェクトが等しいというセマンティックを実装することがよくあります。これにより、コードの記述が反復的になり、保守が脆弱になります (プロパティが追加され、オーバーライドの 1 つまたは両方が更新されません)。

コードは次のようになります (実装に関するコメントは大歓迎です)。

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;
}

私の質問

  1. 実装パターンは健全ですか?
  2. 寄与するコンポーネントの値が十分に分散されている場合、^ は適切ですか? ハッシュが十分に分散されている場合、コレクション要素を結合するときに 31 対 N を乗算する必要がありますか?
  3. このコードは、リフレクションを使用してパブリック プロパティを決定し、ハンド コーディングされたソリューションと一致する式ツリーを構築し、必要に応じて式ツリーを実行するコードに抽象化できるようです。そのアプローチは合理的に見えますか?どこかに既存の実装はありますか?
4

3 に答える 3

4

MSDN は、実際には「変更可能な型に対して Equals などをオーバーロードしないでください」とは言っていません。以前はそう言われましたが、今では次のように言われています。

クラスまたは構造体を定義するときは、その型の値の等価性 (または等価性) のカスタム定義を作成する意味があるかどうかを決定します。通常、型のオブジェクトが何らかのコレクションに追加されることが予想される場合、またはそれらの主な目的が一連のフィールドまたはプロパティを格納することである場合、値の等価性を実装します。

http://msdn.microsoft.com/en-us/library/dd183755.aspx

Dictionary<T,U>それでも、オブジェクトがハッシュされたコレクション ( 、HashSet<T>など)に参加している間、ハッシュ コードの安定性を取り巻く複雑さがあります。

ここで概説するように、私は両方の長所を選択することにしました。

https://stackoverflow.com/a/9752155/141172

于 2012-03-17T17:35:07.810 に答える
1

Equals() と GetHashCode() を頻繁にオーバーライドしていることに気づきました

  • MSDNは言う:変更可能な型のためにEqualsなどをオーバーロードしないでください

寄与するコンポーネントの値が十分に分散されている場合、^ は適切ですか?

  • はい。intプロパティを検討してください。いくつかの (小さい) 素数でシフトすることをお勧めします。
于 2012-03-14T18:45:42.903 に答える
0

おそらく私はここで混乱していますが、onチェックはオーバーライドnullで 0 ではなく 1 を返すべきではありませんか?GetHashCode

そう

MyStringProp == null ? 0 : MyStringProp.GetHashValue()

する必要があります

MyStringProp == null ? 1 : MyStringProp.GetHashValue()
于 2013-04-11T14:26:45.293 に答える