Qual è la differenza tra le interfacce IComparable e IEquatable?


Risposte:


188

IEquatable verifica se due oggetti sono uguali.

IComparable impone un ordinamento totale agli oggetti confrontati.

Ad esempio, IEquatableti direbbe che 5 non è uguale a 7. IComparableti direbbe che 5 viene prima di 7.



10

Oltre alla risposta di Greg D:

Potresti implementarlo IComparablesenza implementarlo IEquatableper una classe in cui un ordinamento parziale ha senso e in cui vuoi decisamente che il consumatore deduca che solo perché CompareTo()restituisce zero, ciò non implica che gli oggetti siano uguali (per qualcosa di diverso dall'ordinamento).


10
Suona molto più come un comparatore di casi speciali che come un oggetto implementato IComparablecorrettamente. Si può venire con un esempio significativo in cui CompareTo(…) == 0non non implica l'uguaglianza? Di certo non posso. In effetti, il contratto di interfaccia (come per MSDN) richiede che ciò CompareTo(…) == 0implichi l'uguaglianza. Per dirla senza mezzi termini, in un caso come il tuo, usa un Comparatoroggetto speciale , non implementare IComparable.
Konrad Rudolph

2
@ Konrad - ho indicato diversi avvertimenti - che il tipo non implementa IEquatable (quindi ovviamente, l'originatore non vuole includere un test di uguaglianza) e che i risultati di CompareTo vengono utilizzati per l'ordinamento, non per valutare l'uguaglianza. Ti metti anche in dubbio quale sia l'uguaglianza rilevante (riferimento, valore, ignorando attributi "arbitrari" - un libro blu di 500 pagine di lunghezza può essere "uguale" a un libro rosso di 500 pagine di lunghezza, ai fini di IComparable)
Damien_The_Unbeliever

4
La tua ultima frase è sbagliata, e questo è l'errore particolare che volevo sottolineare: IComparableè del tutto inappropriato qui. Quello che hai è un ordine molto particolare che si applica solo in una situazione speciale. In tali situazioni, l'implementazione di un generale IComparableè sbagliato. Questo è ciò IComparerper cui ci sono. Ad esempio, le persone non possono essere ordinate in modo significativo. Ma possono essere ordinati in base al loro stipendio, al numero di scarpe, al numero delle loro lentiggini o al loro peso. Quindi, implementeremmo IComparers differenti per tutti questi casi.
Konrad Rudolph

2
@Konrad Rudolph: Che ne dici di qualcosa come una classe "ScheduledEvent", che dovrebbe fare "qualcosa" in un determinato momento? La semantica del tipo implicherebbe un ordinamento semantico naturale molto forte basato sul momento in cui si supponeva che avesse luogo l'azione, ma si potrebbe facilmente avere eventi diversi nello stesso momento. Si potrebbe richiedere l'uso di un IComparer specificato manualmente, ma direi che avere un comparatore integrato nella classe sarebbe più conveniente.
supercat

4
@supercat La comodità è importante, ma non è tutto. La correttezza (come nella coerenza logica) è più importante e il sistema di tipi statici è uno strumento importante per verificare questa coerenza logica. Violando il contratto documentato delle interfacce che implementate, state sovvertendo il sistema dei tipi. Questa non è una buona idea e non la consiglierei mai. Utilizzare un comparatore esterno per tali situazioni.
Konrad Rudolph

7

Come indicato nella pagina MSDN per IEquatable :

L'interfaccia IComparable definisce il CompareTometodo, che determina l'ordinamento delle istanze del tipo di implementazione. L'interfaccia IEquatable definisce il Equalsmetodo, che determina l'uguaglianza delle istanze del tipo di implementazione.

Equals vs. CompareTo


2

IComparable <T> definisce un metodo di confronto specifico per tipo che può essere utilizzato per ordinare o ordinare gli oggetti.

IEquatable <T> definisce un metodo generalizzato che può essere utilizzato per implementare per determinare l'uguaglianza.


Diciamo che hai una classe Persona

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Person p1 = new Person() { Name = "Person 1", Age = 34 };
Person p2 = new Person() { Name = "Person 2", Age = 31 };
Person p3 = new Person() { Name = "Person 3", Age = 33 };
Person p4 = new Person() { Name = "Person 4", Age = 26 };

List<Person> people = new List<Person> { p1, p2, p3, p4 };

Per ordinare questi oggetti puoi usare people.Sort();.

Ma questo genererà un'eccezione.

inserisci qui la descrizione dell'immagine

Framework non sa come ordinare questi oggetti. Devi dire come ordinare l' IComparableinterfaccia di implementazione .

public class Person : IComparable
{
    public string Name { get; set; }
    public int Age { get; set; }

    public int CompareTo(object obj)
    {
        Person otherPerson = obj as Person;
        if (otherPerson == null)
        {
            throw new ArgumentNullException();
        }
        else
        {
            return Age.CompareTo(otherPerson.Age);
        }
    }
}

Questo ordinerà correttamente l'array con il Sort()metodo.


Avanti per confrontare due oggetti puoi usare il Equals()metodo.

var newPerson = new Person() { Name = "Person 1", Age = 34 };
var newPersonIsPerson1 = newPerson.Equals(p1);

Ciò torneràfalse perché il Equalsmetodo non sa come confrontare due oggetti. Pertanto è necessario implementare l' IEquatableinterfaccia e indicare al framework come eseguire il confronto. Estendendo l'esempio precedente sembrerà questo.

public class Person : IComparable, IEquatable<Person>
{
    //Some code hidden

    public bool Equals(Person other)
    {
        if (Age == other.Age && Name == other.Name)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

1
Grazie per questa fantastica spiegazione. Domanda: perché IEquatableusa un generico<Person> e IComparableno?
veuncent
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.