Jestem świadomy faktu, że zawsze muszę zastąpić Equals(object)
i GetHashCode()
podczas implementacji IEquatable<T>.Equals(T)
.Dlaczego Equals (obiekt) wygrywa powyżej Equals (T) podczas korzystania z odziedziczonego obiektu w Hashset lub innych kolekcjach?
Jednak nie rozumiem, dlaczego w niektórych sytuacjach Equals(object)
wygrywa z generycznym Equals(T)
.
Na przykład, dlaczego następujące czynności się zdarzają? Jeśli zadeklaruję IEquatable<T>
dla interfejsu i zaimplementuję dla niego konkretny typ X
, ogólne Equals(object)
jest wywoływane przez Hashset<X>
podczas porównywania elementów tego typu względem siebie. We wszystkich innych sytuacjach, w których co najmniej jedna ze stron jest rzutowana na interfejs, wywoływana jest poprawna Equals(T)
.
Oto przykładowy kod do wykazania:
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)
}
nie powinien "hst.Contains ((IPerson) t1);" nie kompilować? –
@Dennis_E Zobacz drugą połowę mojej odpowiedzi. – Servy
@Dennis_E: to nie jest 'HashSet .Contains', ale' Enumerable.Contains', który akceptuje interfejs. Tak więc jest to powolna wersja, która wylicza wszystkie elementy i porównuje je z 'Equals (IPerson other)' zamiast używać 'GetHashCode'. –