Sono consapevole del fatto che devo sempre eseguire l'override di Equals(object)
e GetHashCode()
quando si implementa IEquatable<T>.Equals(T)
.Perché Equals (oggetto) vince su Equals (T) quando si utilizza un oggetto ereditato in Hashset o altre raccolte?
Tuttavia, non capisco, perché in alcune situazioni lo Equals(object)
vince sul generico Equals(T)
.
Ad esempio, perché succede? Se dichiaro IEquatable<T>
per un'interfaccia e implementiamo un tipo concreto X
per questo, il generale Equals(object)
viene chiamato da un Hashset<X>
quando si confrontano gli elementi di quel tipo l'uno contro l'altro. In tutte le altre situazioni in cui almeno uno dei lati viene trasmesso all'interfaccia, viene chiamato il Equals(T)
corretto.
Ecco un esempio di codice per dimostrare:
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)
}
non dovrebbe 'hst.Contains ((IPerson) t1);' impossibile compilare? –
@Dennis_E Guarda la seconda metà della mia risposta. – Servy
@Dennis_E: non è 'HashSet .Contains' ma' Enumerable.Contains' che accetta l'interfaccia. Quindi questa è la versione lenta che enumera tutti gli elementi e li confronta con 'Equals (IPerson altro)' invece di usare 'GetHashCode'. –