2008-09-16 4 views
6

リファレンスタイプのEquals()の実装は、それよりも難しくなります。私の現在の標準的な実装では、このように書きます:参照型のためのEquals()の "最良の"正規の実装は何ですか?

public bool Equals(MyClass obj) 
{ 
    // If both refer to the same reference they are equal. 
    if(ReferenceEquals(obj, this)) 
    return true; 

    // If the other object is null they are not equal because in C# this cannot be null. 
    if(ReferenceEquals(obj, null)) 
    return false; 

    // Compare data to evaluate equality  
    return _data.Equals(obj._data); 
} 

public override bool Equals(object obj) 
{ 
    // If both refer to the same reference they are equal. 
    if(ReferenceEquals(obj, this)) 
    return true; 

    // If the other object is null or is of a different types the objects are not equal. 
    if(ReferenceEquals(obj, null) || obj.GetType() != GetType()) 
    return false; 

    // Use type-safe equality comparison 
    return Equals((MyClass)obj); 
} 

public override int GetHashCode() 
{ 
    // Use data's hash code as our hashcode 
    return _data.GetHashCode(); 
} 

私は、これはすべてのコーナー(相続など)のケースをカバーしていますが、私は間違っているかもしれだと思います。皆さんはどう思いますか?

答えて

4

私はこれまでかなりの包括的なガイドを書いていました。まず、equalsの実装を共有する必要があります(オブジェクトを取るオーバーロードは、厳密に型指定されたオブジェクトを取るオブジェクトに渡す必要があります)。さらに、GetHashCodeをオーバーライドする必要があるため、オブジェクトが不変でなければならないなどのことを考慮する必要があります。詳細:

http://gregbeech.com/blog/implementing-object-equality-in-dotnet

+0

私の実装は "共有"です。ご覧のように、Equals(Object)の最後にはEquals(MyClass)が呼び出されます。 私はmutabilityとGetHashCode()の問題を認識しています。それは重要な観察です。それは私に何度か噛み付いている。読み込み専用の "クラス"を宣言する "簡単な"方法はないというのは残念です。 –

+0

リンクは現在壊れています。 – Restuta

0

値の型と参照の型のどちらを書き込むかによって異なります。ソート可能な値の型については、私はこれをお勧めします: A code snippet for Visual Studio 2005 that implements a skeleton value type adhering to Framework Design Guidelines

+0

私は、値型の実装が異なっていることを知っています。私は参照型について尋ねました。 –

+0

リンクが切れています。 :| – Restuta

+0

私は壊れたリンクを修正しました... –

0

継承に関しては、私はOOパラダイムにその魔法をさせるべきだと思います。

特に、GetType()のチェックは削除する必要があります。これにより、多形性が破られる可能性があります。

+1

私は同意しません。 Fruitクラスから派生したAppleクラスとOrangeクラスがあるとします。 Equals in Fruitの実装でGetType()チェックを削除した場合、すべての派生クラスがEquals()を適切にオーバーライドしない限り、AppleをOrangesと比較できます。それは非常に迅速に乱雑になる可能性があります。 –

0

私はchakritに同意します。異種のオブジェクトは、同じデータまたはIDを持つ場合、意味的に等価にする必要があります。それはまた、参照型かどうthis._dataがnullでないことを

public override bool Equals(object obj) 
    { 
     var other = obj as MyClass; 
     if (other == null) return false; 

     return this.data.Equals(other.data); 
    } 
+0

私はあなたに同意しません。これにより、Appleとオレンジを比較することができます。 –

+0

ポイントは多分あなたがそれらを平等にしたいと思うことです。 GetTypeチェックでは、プロキシの使用は許可されません。 2つの同一のオブジェクトがあります.1つは異なるタイプのコンテナ内にラップされていますが、同じものとして識別したいとします。 –

+0

@SantiagoPalladino: 'Object.Equals'よりも同義語の定義が狭い等価比較子を定義することはしばしば意味があります。たとえば、.netは文字列が異なっていても "HELLO"を "Hello"または "heLlO"と同等と見なすさまざまな大文字と小文字を区別する文字列比較器を定義します。そのような比較者は、異なるタイプの等しいオブジェクトとして受け入れることができます。私は非常にObject.Equalsをオーバーライドするオブジェクトの概念を嫌い、明示的にオブジェクトが提供されていない限り、異なる型のオブジェクトが等しくないと判断するような緩やかな同値関係を定義します... – supercat

1

良いの希望:

は個人的に、私は次のように使用します。

public bool Equals(MyClass obj) 
{ 
    if (obj == null) { 
     return false; 
    } 
    else { 
     return (this._data != null && this._data.Equals(obj._data)) 
         || obj._data == null; 
    } 
} 

public override bool Equals(object obj) 
{ 
    if (obj == null || !(obj is MyClass)) { 
     return false; 
    } 
    else { 
     return this.Equals((MyClass)obj); 
    } 
} 

public override int GetHashCode() { 
    return this._data == null ? 0 : this._data.GetHashCode(); 
} 
+0

あなたは正しいです。これは、 "Equals"の背後にある概念を証明するための "標準的な"実装に過ぎません。私の "本当の"実装は通常、a.Equals(b)の代わりにEquals(a、b)を使って実装されています。 –

関連する問題