IEquatableとObject.Equals()をオーバーライドするだけの違いは何ですか?


185

Foodクラスがの別のインスタンスと等しい場合はいつでもテストできるようにしたいFood。後でリストに対して使用し、そのList.Contains()メソッドを使用したいと思います。実装するIEquatable<Food>か、単にオーバーライドする必要がありますObject.Equals()か?MSDNから:

このメソッドは、T(リスト内の値のタイプ)に対するIEquatable.Equalsメソッドのオブジェクトの実装によって定義されているデフォルトの等値比較子を使用して、等値を決定します。

だから私の次の質問は:.NETフレームワークのどの関数/クラスが利用するのObject.Equals()ですか?そもそも使った方がいいですか?


3
ここでは非常に良い説明blogs.msdn.com/b/jaredpar/archive/2009/01/15/...
nawfal

回答:


214

主な理由はパフォーマンスです。ジェネリック医薬品は、.NET 2.0で導入されたとき、彼らは、次のようなきちんとしたクラスの束を追加することができましたList<T>Dictionary<K,V>HashSet<T>、などのこれらの構造を多用するGetHashCodeEquals。しかし、値型の場合、これにはボクシングが必要でした。IEquatable<T>構造体に厳密に型指定されたEqualsメソッドを実装させるため、ボクシングは必要ありません。したがって、ジェネリックコレクションで値型を使用する場合のパフォーマンスが大幅に向上します。

参照型にはそれほどメリットはありませんが、IEquatable<T>実装では、System.Object頻繁に呼び出される場合に違いが生じるキャストを回避できます。

ただし、Jared Parsonのブログに記載されているように、オブジェクトのオーバーライドを実装する必要があります。


参照型の間にキャストはありますか?キャストは、ある種類のオブジェクトから別の種類のオブジェクトに明らかでないキャストを割り当てるときにコンパイラに作成する「ステートメント」にすぎないと常に思っていました。これは、コンパイル後、コードがそこにキャストがあったことさえ知らないということです。
食欲をそそるエリジウム2010

7
これはC ++には当てはまりますが、タイプセーフを強制する.NET言語には当てはまりません。ランタイムキャストがあり、キャストが成功しない場合、例外がスローされます。そのため、キャストに支払うランタイムペナルティが少しあります。コンパイラはアウェイアップキャストを最適化できます。たとえば、object o =(object) "string"; しかし、ダウンキャスト-文字列s =(文字列)o; -実行時に発生する必要があります。
ジョシュ

1
そうですか。たまたま、.NETに関するそのような「より深い」情報を入手できる場所がありますか?ありがとう!
食欲をそそるエリジウム2010

7
私は、Jeff RichterによるC#およびJon SkeetによるC#のC#を介してCLRを推奨します。ブログに関しては、Wintellectブログ、msdnブログなどが良い
Josh

IEquatable<T>インタフェースDO何か以上が含まれるように、開発者を思い出させる public bool Equals(T other) 、クラスまたは構造体のメンバーを?インターフェースの有無は、実行時に違いはありません。の過負荷Equalsが必要なすべてのように見えるでしょう。
mikemay

48

MSDNによると:

を実装する場合IEquatable<T>Object.Equals(Object)、およびの基本クラスの実装もオーバーライドして、GetHashCode それらの動作がIEquatable<T>.Equals メソッドの動作と一致するようにする必要があります 。overrideを行う場合 Object.Equals(Object)、オーバーライドされた実装はEquals(System.Object, System.Object)、クラスの静的メソッドの呼び出しでも呼び出されます。これにより、Equalsメソッドのすべての呼び出しで一貫した結果が返されます。

したがって、クラスの使用方法に応じてどちらかを呼び出すことができることを除いて、2つの間に実際の機能的な違いはないようです。パフォーマンスの観点からは、それに関連するボクシング/アンボクシングのペナルティがないため、ジェネリックバージョンを使用することをお勧めします。

論理的な観点からは、インターフェイスを実装することもお勧めします。オブジェクトをオーバーライドしても、クラスが実際に等値であるとは誰にもわかりません。オーバーライドは、何もしないクラスまたは浅い実装の場合があります。インターフェイスを使用すると、「ねえ、これは等価性チェックに有効です!」それはただより良いデザインです。


9
構造体は、ディクショナリまたは同様のコレクションでキーとして使用される場合、(eOwnTypeの)iEquatableを確実に実装する必要があります。パフォーマンスが大幅に向上します。継承不可のクラスは、IEOtable(theirOwnTypeの)を実装することにより、パフォーマンスがわずかに向上します。継承可能なクラスはIEquatableを//実装しないでください。
スーパーキャット

30

ジョシュが言ったことを実際的な例で拡張する。ジョシュへの+1-私は私の答えに同じことを書き込もうとしていた。

public abstract class EntityBase : IEquatable<EntityBase>
{
    public EntityBase() { }

    #region IEquatable<EntityBase> Members

    public bool Equals(EntityBase other)
    {
        //Generic implementation of equality using reflection on derived class instance.
        return true;
    }

    public override bool Equals(object obj)
    {
        return this.Equals(obj as EntityBase);
    }

    #endregion
}

public class Author : EntityBase
{
    public Author() { }
}

public class Book : EntityBase
{
    public Book() { }
}

このようにして、すべての派生クラスに対してそのまま使用できる再利用可能なEquals()メソッドがあります。


もう1つ質問します。(EntityBase)objの代わりに「obj as EntityBase」を使用する利点は何ですか?スタイルの問題だけですか、それとも何か利点がありますか?
食欲をそそるエリジウム2010

22
「obj as EntityBase」の場合-objがタイプEntityBaseでない場合、「null」を渡してエラーや例外なしに続行しますが、「(EntityBase)obj」の場合は、objを強制的にキャストしようとしますEntityBaseに渡され、objがEntityBaseタイプでない場合は、InvalidCastExceptionがスローされます。はい、「as」は参照型にのみ適用できます。
これ。__curious_geek 2010

1
Jared ParのブログへのJoshのリンクは、GetHashCodeもオーバーライドする必要があることを示唆しているようです。これはそうではありませんか?
友好的な2014

3
私はあなたの実装が提供する追加の価値を本当に得ていません。抽象基本クラスが解決する問題を明確にできますか?
Mert Akcakaya、2015年

1
@Amicable-はい、Object.Equals(Object)をオーバーライドする場合は常に、コンテナが機能するようにGetHashCodeもオーバーライドする必要があります。
ナムフォード2015年

0

を呼び出すとobject.Equals、値型の高価なボックス化が強制されます。これはパフォーマンス重視のシナリオでは望ましくありません。解決策はを使用することIEquatable<T>です。

public interface IEquatable<T>
{
  bool Equals (T other);
}

背後にIEquatable<T>ある考え方は、同じ結果をobject.Equalsより迅速に提供することです。制約where T : IEquatable<T>は、以下のようなジェネリック型で使用する必要があります。

public class Test<T> where T : IEquatable<T>
{
  public bool IsEqual (T a, T b)
  {
    return a.Equals (b); // No boxing with generic T
  }
}

それ以外の場合は、にバインドしslower object.Equals()ます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.