参照型に対する 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();
}
これはあらゆる隅々のケース(相続など)をカバーしていると思いますが、間違っている可能性があります。皆さんはどう思いますか?
解決
私は少し前にこれに関するかなり包括的なガイドを書きました。まず、equals 実装を共有する必要があります (つまり、オブジェクトを受け取るオーバーロードは、厳密に型指定されたオブジェクトを受け取るオーバーロードに渡される必要があります)。さらに、GetHashCode をオーバーライドする必要があるため、オブジェクトは不変である必要があるなどのことを考慮する必要があります。詳細はこちら:
http://gregbeech.com/blog/implementing-object-equality-in-dotnet
他のヒント
this._data が参照型でもある場合は、null でないことを願ったほうがよいでしょう。
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();
}
継承に関しては、OO パラダイムの魔法に任せるべきだと思います。
具体的には、 GetType()
チェックは削除する必要があります。最終的にポリモーフィズムが壊れる可能性があります。
私はchakritに同意します。異なるタイプのオブジェクトは、同じデータまたはIDを持つ場合、意味的に同等であることが許可されるべきです。
個人的には以下のものを使っています。
public override bool Equals(object obj)
{
var other = obj as MyClass;
if (other == null) return false;
return this.data.Equals(other.data);
}
それは、値型を記述しているか参照型を記述しているかによって異なります。並べ替え可能な値の型については、これをお勧めします。フレームワーク設計ガイドラインに準拠したスケルトン値型を実装する Visual Studio 2005 のコード スニペット