Quando utilizzare IComparable <T> vs. IComparer <T>


Risposte:


96

Ebbene non sono proprio la stessa cosa in quanto IComparer<T>è implementato su un tipo che è in grado di confrontare due oggetti diversi mentre IComparable<T>è implementato su tipi che sono in grado di confrontarsi con altre istanze dello stesso tipo.

Tendo a usare IComparable<T>per i momenti in cui ho bisogno di sapere come un'altra istanza si riferisce thisall'istanza. IComparer<T>è utile per l'ordinamento delle collezioni in quanto le IComparer<T>posizioni fuori dal confronto.


9
IComparer <T> ti consente anche di avere una classe per ogni tipo di ordinamento che desideri. Esempio; PersonLastFirstNameComparer, PersonFirstLastNameComparer o PersonAgeComparer.
Eric Schneider

C'è un modo semplice per ricordarli? Tendo a doverlo cercare ogni volta.
amadib

59
@amadib pensa IComparablecome sono paragonabile . il che significa che posso essere paragonato a qualcos'altro. E leggi IComparercome sono un comparatore, semplicemente confronto, il che significa che confronto alcune cose.
nawfal

@newfal Avresti dovuto metterlo come risposta. Penso che sia la migliore spiegazione qui.
Gene S

42

Utilizzare IComparable<T>quando la classe ha un confronto intrinseco.

Utilizzare IComparer<T>quando si desidera un metodo di confronto diverso dal confronto intrinseco della classe, se disponibile.


28

Dipende dall'entità. Ad esempio, seguendo per una classe come "Studente", avrà senso avere IComparable basato su Nome.

class Student : IComparable 
{
    public string Name { get; set; }
    public int MathScore { get; set; }
    public int EnglishScore { get; set; }

    public int TotalScore 
    {
        get
        {
            return this.MathScore + this.EnglishScore; 
        }
    }

    public int CompareTo(object obj)
    {
        return CompareTo(obj as Student);  
    }

    public int CompareTo(Student other)
    {
        if (other == null)
        {
            return 1;
        }
        return this.Name.CompareTo(other.Name);  
    }
}

Ma se un insegnante "A" desidera confrontare gli studenti in base a MathScore e l'insegnante "B" desidera confrontare gli studenti in base a EnglishScore. Sarà una buona idea implementare IComparer separatamente. (Più simile a un modello strategico)

class CompareByMathScore : IComparer<Student>
{
    public int Compare(Student x, Student y)
    {
        if (x.MathScore > y.MathScore)
          return 1;
        if (x.MathScore < y.MathScore)
          return -1;
        else
          return 0;
    }
}

Rendi statico il metodo Compare per un facile utilizzo.
gennaio

9

Tutto dipende dal fatto che il tuo tipo sia mutevole o meno. È necessario implementare IComparable solo sui tipi non modificabili. Si noti che se si implementa IComparable, è necessario sostituire Equals, insieme agli operatori ==,! =, <E> (vedere l'avviso di analisi del codice CA1036).

Citando Dave G da questo post del blog :

Ma la risposta corretta è implementare IComparer invece di IComparable se gli oggetti sono modificabili e passare un'istanza di IComparer alle funzioni di ordinamento quando necessario.

Poiché IComparer è solo un oggetto usa e getta utilizzato per l'ordinamento in quel momento, il tuo oggetto può avere qualsiasi semantica mutabile che desideri. Inoltre, non richiede né suggerisce l'uso di Equals, GetHashCode o ==: sei libero di definirlo nel modo che preferisci.

Infine, puoi definire più IComparer per il tuo tipo per l'ordinamento su campi diversi o con regole diverse. Questo è molto più flessibile dell'essere bloccati con una definizione.

In breve: utilizzare IComparable per i tipi di valore e IComparer per i tipi di riferimento.


6

Spiegazione semplice tramite una storia

Pallacanestro del liceo. È una scelta del cortile della scuola per le squadre. Voglio avere le persone più alte / migliori / più veloci nella mia squadra. Cosa faccio?

Interfaccia IComparer : confronta due persone separate

  • Questo mi permette di confrontare due ragazzi in fila ......... fondamentalmente è così. Fred vs John .......... li inserisco in una classe concreta che implementa l'interfaccia. Compare(Fred, John)e sputa chi è il migliore.

Che mi dici di IComparable? - Confronta te stesso con qualcun altro

Sei stato su FB di recente? Vedi altre persone che fanno cose interessanti: viaggiare per il mondo, creare invenzioni, mentre io sto facendo qualcosa di non altrettanto interessante - beh, quello che stiamo facendo è usare l'interfaccia IComparable.

  • Stiamo confrontando l'istanza corrente (te stesso) con un altro oggetto (qualcun altro) che è dello stesso tipo (persona).

E la classe Comparer?

La classe Comparer è una classe base astratta che implementa l'interfaccia IComparer. Dovresti derivare da questa classe per avere un'implementazione concreta. comunque, Microsoft consiglia di utilizzare la classe Comparer anziché implementare l'interfaccia IComparer:

Si consiglia di derivare dalla classe Comparer invece di implementare l'interfaccia IComparer, poiché la classe Comparer fornisce un'implementazione dell'interfaccia esplicita del metodo IComparer.Compare e della proprietà Default che ottiene l'operatore di confronto predefinito per l'oggetto.

Sommario

  • IComparer: allinea due cose e confronta.
  • IComparable: confronta te stesso con gli altri su FB.

Spero che le storie ti aiutino a ricordare.


1
Mi piace il tuo modo di illustrare il concetto chiave. Potrebbe essere meglio se includi la classe Comparer (T) in questo concorso. Anche non è incluso nella domanda. :)
Kevman

4

Come altri hanno già detto, non fanno la stessa cosa.

In ogni caso, in questi giorni tendo a non usare IComparer. Perché dovrei? La sua responsabilità (un'entità esterna usata per confrontare due oggetti) può essere gestita in modo molto più pulito con un'espressione lambda, simile a come funzionano la maggior parte dei metodi di LINQ. Scrivi un lambda veloce che prenda gli oggetti da confrontare come argomenti e restituisca un valore bool. E se l'oggetto definisce la propria operazione di confronto intrinseca, può invece implementare IComparable.


1
-1: restituire un bool non è equivalente a IComparer. IComparer restituisce un valore che può essere minore di zero / zero / maggiore di zero e viene in genere utilizzato per l'ordinamento.
Joe,

E quando questo è ciò di cui hai bisogno, restituisci invece un int (o meglio ancora, un enum). È davvero un grosso problema?
jalf

2
Puoi anche restituire un bool, poiché less than è l'unica operazione necessaria per ordinare una sequenza.
jalf

un'implementazione di IComparer deve essere definita solo una volta, se è necessario utilizzare la logica di ordinamento in più punti, l'espressione lambda dovrà essere scritta più volte.
dal

oɔɯǝɹ - Quindi puoi memorizzare un riferimento al delegato che è stato scritto come espressione lambda e riutilizzarlo.
jpierson

3

IComparable dice che un oggetto può essere paragonato a un altro. IComparer è un oggetto che può confrontare due elementi qualsiasi.


2

IComparer è un'interfaccia che viene utilizzata per ordinare l'Array, questa interfaccia costringerà la classe a implementare il metodo Compare (T x, T y), che confronterà i due oggetti. L'istanza della classe che ha implementato questa interfaccia viene utilizzata nell'ordinamento di Array.

IComparable è un'interfaccia implementata nel tipo che deve confrontare i due oggetti dello stesso tipo, questa interfaccia comparabile costringerà la classe a implementare il seguente metodo CompareTo (T obj)

IEqualityComparer è un'interfaccia che viene utilizzata per trovare l'oggetto che sia uguale o meno, ora lo vedremo in un esempio in cui dobbiamo trovare il Distinct di un oggetto in una raccolta. Questa interfaccia implementerà un metodo Equals (T obj1, T obj2)

Ora prendiamo un esempio, abbiamo una classe Employee, in base a questa classe dobbiamo creare una Collection. Ora abbiamo i seguenti requisiti.

Ordina la matrice utilizzando la classe Array 2. Serve una raccolta utilizzando Linq: Rimuovi il duplicato, Ordina dal più alto al più basso, Rimuovi un ID dipendente

abstract public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address { set; get; }
}

public enum SortType
{
    ByID,
    BySalary
}

public class EmployeeIdSorter: IComparer {public int Compare (Employee x, Employee y) {if (x.Id <y.Id) return 1; altrimenti se (x.Id> y.Id) restituisce -1; altrimenti restituisce 0; }}

    public class EmployeeSalarySorter : IComparer<Employee>
    {
        public int Compare(Employee x, Employee y)
        {
            if (x.Salary < y.Salary)
                return 1;
            else if (x.Salary > y.Salary)
                return -1;
            else
                return 0;
        }
    }

Per maggiori informazioni fare riferimento a http://dotnetvisio.blogspot.in/2015/12/usage-of-icomparer-icomparable-and.html

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.