Quand utiliser IComparable <T> Vs. IComparer <T>

Réponses:

96

Eh bien, ils ne sont pas tout à fait la même chose que celle IComparer<T>implémentée sur un type capable de comparer deux objets différents alors qu'elle IComparable<T>est implémentée sur des types capables de se comparer avec d'autres instances du même type.

J'ai tendance à utiliser IComparable<T>lorsque j'ai besoin de savoir comment une autre instance se rapporte à une thisinstance. IComparer<T>est utile pour trier les collections en IComparer<T>dehors de la comparaison.

Andrew Hare
la source
9
IComparer <T> vous permet également d'avoir une classe pour chaque type de tri souhaité. Exemple; PersonLastFirstNameComparer, PersonFirstLastNameComparer ou PersonAgeComparer.
Eric Schneider
Existe-t-il un moyen facile de s'en souvenir? J'ai tendance à devoir le chercher à chaque fois.
amadib
59
@amadib pense IComparableque je suis comparable . ce qui signifie que je peux être comparé à autre chose. Et lu IComparercomme je suis un comparateur, je compare simplement ce qui signifie que je compare certaines choses.
nawfal
@newfal Vous auriez dû mettre ceci comme réponse. Je pense que c'est la meilleure explication ici.
Gene S
42

À utiliser IComparable<T>lorsque la classe a une comparaison intrinsèque.

À utiliser IComparer<T>lorsque vous souhaitez une méthode de comparaison autre que la comparaison intrinsèque de la classe, si elle en a une.

Yfeldblum
la source
28

Cela dépend de l'entité. Par exemple suivant pour une classe comme "Student", il sera logique d'avoir IComparable basé sur Name.

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);  
    }
}

Mais si un enseignant «A» veut comparer des élèves sur la base de MathScore et que l'enseignant «B» veut comparer des élèves sur la base de EnglishScore. Ce sera une bonne idée d'implémenter IComparer séparément. (Plus comme un modèle de stratégie)

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;
    }
}
Ajay Bhosale
la source
Rendez la méthode Compare statique pour une utilisation facile.
janvier
9

Tout dépend si votre type est mutable ou non. Vous devez seulement mettre en œuvre IComparable sur les types non-mutables. Notez que si vous implémentez IComparable, vous devez remplacer Equals, ainsi que les opérateurs ==,! =, <Et> (voir l'avertissement d'analyse de code CA1036).

Citant Dave G à partir de ce billet de blog :

Mais la bonne réponse est d'implémenter IComparer au lieu de IComparable si vos objets sont mutables et de transmettre une instance de IComparer aux fonctions de tri si nécessaire.

Étant donné que IComparer n'est qu'un objet jetable utilisé pour le tri à ce moment-là, votre objet peut avoir n'importe quelle sémantique modifiable que vous souhaitez. De plus, il ne nécessite ni ne suggère d'utiliser Equals, GetHashCode ou == - vous êtes libre de le définir de la manière qui vous convient.

Enfin, vous pouvez définir plusieurs IComparer pour votre type pour le tri sur différents champs ou avec des règles différentes. C'est beaucoup plus flexible que d'être coincé avec une définition.

En bref: utilisez IComparable pour les types valeur et IComparer pour les types référence.

M. Bungle
la source
6

Explication simple via une histoire

Basket-ball de lycée. C'est un choix de cour d'école pour les équipes. Je veux obtenir les personnes les plus grandes / les meilleures / les plus rapides de mon équipe. Que fais-je?

Interface IComparer - Comparez deux personnes différentes

  • Cela me permet de comparer deux types alignés ......... c'est fondamentalement tout. Fred vs John .......... je les jette dans une classe concrète qui implémente l'interface. Compare(Fred, John)et il crache qui est le meilleur.

Et IComparable? - Comparez-vous avec quelqu'un d'autre

Avez-vous été sur FB récemment? Vous voyez d'autres gens faire des choses sympas: parcourir le monde, créer des inventions, pendant que je fais quelque chose qui n'est pas aussi cool - eh bien, ce que nous faisons, c'est utiliser l'interface IComparable.

  • Nous comparons l'instance actuelle (vous-même) avec un autre objet (quelqu'un d'autre) qui est du même type (personne).

Qu'en est-il de la classe Comparer?

La classe Comparer est une classe de base abstraite qui implémente l'interface IComparer. Vous devez dériver de cette classe pour avoir une implémentation concrète. Quoi qu'il en soit, Microsoft vous recommande d'utiliser la classe Comparer plutôt que d'implémenter l'interface IComparer:

Nous vous recommandons de dériver de la classe Comparer au lieu d'implémenter l'interface IComparer, car la classe Comparer fournit une implémentation d'interface explicite de la méthode IComparer.Compare et de la propriété Default qui obtient le comparateur par défaut pour l'objet.

Résumé

  • IComparer - alignez deux choses et comparez.
  • IComparable - comparez-vous avec les autres sur FB.

J'espère que les histoires vous aideront à vous souvenir.

BKSpurgeon
la source
1
J'aime votre façon d'illustrer le concept clé. Cela pourrait être mieux si vous incluez la classe Comparer (T) dans ce concours. Même ce n'est pas inclus dans la question. :)
Kevman
4

Comme d'autres l'ont dit, ils ne font pas la même chose.

Dans tous les cas, ces jours-ci, j'ai tendance à ne pas utiliser IComparer. Pourquoi aurais-je? Sa responsabilité (une entité externe utilisée pour comparer deux objets) peut être gérée beaucoup plus clairement avec une expression lambda, similaire au fonctionnement de la plupart des méthodes LINQ. Écrivez un lambda rapide qui prend les objets à comparer comme arguments, et renvoie un booléen. Et si l'objet définit sa propre opération de comparaison intrinsèque, il peut implémenter IComparable à la place.

jalf
la source
1
-1: renvoyer un booléen n'est pas équivalent à IComparer. IComparer renvoie une valeur qui peut être inférieure à zéro / zéro / supérieure à zéro et est généralement utilisée pour le tri.
Joe le
Et quand c'est ce dont vous avez besoin, vous retournez un int (ou mieux encore, une énumération). Est-ce vraiment un gros problème?
jalf
2
Vous pouvez même renvoyer un booléen, car moins que est la seule opération dont vous avez besoin pour trier une séquence.
jalf
une implémentation IComparer ne doit être définie qu'une seule fois, si vous devez utiliser la logique de tri à plusieurs endroits, l'expression lambda devra être écrite plusieurs fois.
2010
oɔɯǝɹ - Vous pouvez ensuite stocker une référence au délégué qui a été écrite en tant qu'expression lambda et la réutiliser également.
jpierson
3

IComparable dit qu'un objet peut être comparé à un autre. IComparer est un objet qui peut comparer deux éléments quelconques.

Neil Barnwell
la source
2

IComparer est une interface qui permet de trier le tableau, cette interface forcera la classe à implémenter la méthode Compare (T x, T y), qui comparera les deux objets. L'instance de la classe qui a implémenté cette interface est utilisée dans le tri du tableau.

IComparable est une interface implémentée dans le type qui a besoin de comparer les deux objets du même type, Cette interface comparable forcera la classe à implémenter la méthode suivante CompareTo (T obj)

IEqualityComparer est une interface qui est utilisée pour trouver l'objet, qu'il soit égal ou non, nous allons maintenant le voir dans un exemple où nous devons trouver le distinct d'un objet dans une collection. Cette interface implémentera une méthode Equals (T obj1, T obj2)

Maintenant, nous prenons un exemple, nous avons une classe Employee, basée sur cette classe, nous devons créer une collection. Nous avons maintenant les exigences suivantes.

Trier le tableau à l'aide de la classe Array 2. Besoin d'une collection utilisant Linq: supprimer le duplicata, classer par ordre décroissant, supprimer un identifiant d'employé

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

public enum SortType
{
    ByID,
    BySalary
}

Classe publique EmployeeIdSorter: IComparer {public int Compare (Employee x, Employee y) {if (x.Id <y.Id) return 1; else if (x.Id> y.Id) return -1; sinon retourne 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;
        }
    }

Pour plus d'informations, référez-vous ci-dessous http://dotnetvisio.blogspot.in/2015/12/usage-of-icomparer-icomparable-and.html

Rajesh G
la source