20

Equals(object)GetHashCode()実装するときは常にオーバーライドする必要があるという事実を認識していますIEquatable<T>.Equals(T)

Equals(object)ただし、状況によっては、ジェネリックよりも優先される理由がわかりませんEquals(T)

たとえば、なぜ次のようなことが起こっているのでしょうか? インターフェイスを宣言IEquatable<T>し、具体的な型を実装すると、それらの型の項目を相互に比較するときXに、ジェネラルEquals(object)が a によって呼び出されます。Hashset<X>サイドの少なくとも 1 つがインターフェイスにキャストされる他のすべての状況では、正しいものEquals(T)が呼び出されます。

デモ用のコード サンプルを次に示します。

public interface IPerson : IEquatable<IPerson> { }

//Simple example implementation of Equals (returns always true)
class Person : IPerson
{
    public bool Equals(IPerson other)
    {
        return true;
    }

    public override bool Equals(object obj)
    {
        return true;
    }

    public override int GetHashCode()
    {
        return 0;
    }
}

private static void doEqualityCompares()
{
    var t1 = new Person();

    var hst = new HashSet<Person>();
    var hsi = new HashSet<IPerson>();

    hst.Add(t1);
    hsi.Add(t1);

    //Direct comparison
    t1.Equals(t1);                  //IEquatable<T>.Equals(T)

    hst.Contains(t1);               //Equals(object) --> why? both sides inherit of IPerson...
    hst.Contains((IPerson)t1);      //IEquatable<T>.Equals(T)

    hsi.Contains(t1);               //IEquatable<T>.Equals(T)
    hsi.Contains((IPerson)t1);      //IEquatable<T>.Equals(T)
}
4

2 に答える 2

2

IComparable<in T>に対して反変でありT、 を実装IComparable<Person>する型は自動的に の実装と見なされますがIComparable<IPerson>、この型IEquatable<T>はシール型、特に構造体での使用を意図しています。両方とObject.GetHashCode()一致しているという要件は、一般に、後者の 2 つのメソッドが同じように動作する必要があることを意味します。これは、一方が他方に連鎖する必要があることを意味します。構造体を適切な型の実装に直接渡すことと、構造体の boxed-heap-object 型のインスタンスを構築し、IEquatable<T>.Equals(T)Object.Equals(Object)IEquatable<T>Equals(Object)実装はそこから構造体データをコピーしますが、そのようなパフォーマンスの違いは参照型では存在しません。IEquatable<T>.Equals(T)Equals(Object)が同等になり、継承可能な参照型である場合T、次の間に意味のある違いはありません。

bool Equals(MyType obj)
{
  MyType other = obj as MyType;
  if (other==null || other.GetType() != typeof(this))
    return false;
  ... test whether other matches this
}

bool Equals(MyType other)
{
  if (other==null || other.GetType() != typeof(this))
    return false;
  ... test whether other matches this
}

後者は 1 つの型キャストを節約できますが、2 つのメソッドを持つことを正当化するのに十分なパフォーマンスの違いをもたらす可能性は低いです。

于 2015-02-10T19:26:54.707 に答える