Когда использовать IComparable <T> Vs. IComparer <T>

101

Я пытаюсь понять, какой из этих интерфейсов мне нужно реализовать. По сути, они оба делают одно и то же. Когда я буду использовать одно вместо другого?

Мика
источник
Большие примеры и объяснения можно найти здесь: support.microsoft.com/nl-nl/help/320727/...
Jan

Ответы:

96

Ну, это не совсем то же самое, что IComparer<T>реализовано в типе, способном сравнивать два разных объекта, в то время IComparable<T>как реализовано в типах, которые могут сравнивать себя с другими экземплярами того же типа.

Я обычно использую, IComparable<T>когда мне нужно знать, как другой экземпляр относится к thisэкземпляру. IComparer<T>полезен для сортировки коллекций, поскольку IComparer<T>стоит вне сравнения.

Эндрю Хэйр
источник
9
IComparer <T> также позволяет вам иметь класс для каждого типа сортировки, который вы хотите. Пример; PersonLastFirstNameComparer, PersonFirstLastNameComparer или PersonAgeComparer.
Эрик Шнайдер
Есть ли простой способ их запомнить? Я склонен каждый раз искать его.
amadib 07
59
@amadib думаю, IComparableчто я сравним . а значит, меня можно сравнить с чем-то другим. И читая, IComparerкак я сравниваю, я просто сравниваю, что означает, что я сравниваю некоторые вещи.
nawfal 06
@newfal Ты должен был поставить это как ответ. Я думаю, что это лучшее объяснение здесь.
Gene S
42

Используйте, IComparable<T>когда у класса есть внутреннее сравнение.

Используйте, IComparer<T>если вам нужен метод сравнения, отличный от внутреннего сравнения класса, если он есть.

Yfeldblum
источник
28

Это зависит от сущности. Например, следуя примеру класса «Студент», имеет смысл иметь IComparable на основе имени.

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

Но если учитель «А» хочет сравнить учеников на основе MathScore, а учитель «Б» хочет сравнить учеников на основе EnglishScore. Было бы неплохо реализовать IComparer отдельно. (Больше похоже на шаблон стратегии)

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;
    }
}
Аджай Бхосале
источник
Сделайте метод Compare статическим для удобства использования.
янв.
9

Все зависит от того, является ли ваш тип изменчивым или нет. Вы должны реализовывать IComparable только для неизменяемых типов. Обратите внимание, что если вы реализуете IComparable, вы должны переопределить Equals вместе с операторами ==,! =, <И> (см. Предупреждение анализа кода CA1036).

Цитата Дэйва Джи из этого сообщения в блоге :

Но правильный ответ - реализовать IComparer вместо IComparable, если ваши объекты изменчивы, и при необходимости передать экземпляр IComparer функциям сортировки.

Поскольку IComparer - это просто одноразовый объект, используемый для сортировки в этот момент времени, ваш объект может иметь любую изменяемую семантику, которую вы пожелаете. Кроме того, он не требует и даже не предлагает использовать Equals, GetHashCode или == - вы можете определять его как угодно.

Наконец, вы можете определить несколько IComparer для своего типа для сортировки по разным полям или с разными правилами. Это гораздо более гибко, чем зацикливаться на одном определении.

Вкратце: используйте IComparable для типов значений и IComparer для ссылочных типов.

Мистер Бангл
источник
6

Простое объяснение через рассказ

Баскетбол средней школы. Это выбор школьного двора для команд. Я хочу собрать в команду самых высоких / лучших / самых быстрых людей. Что мне делать?

Интерфейс IComparer - Сравните двух людей разных людей

  • Это позволяет мне сравнивать любых двух парней в очереди ......... в основном все. Фред против Джона .......... я добавляю их в конкретный класс, реализующий интерфейс. Compare(Fred, John)и выплевывает, кто лучше.

А как насчет IComparable? - Сравните себя с кем-то другим

Вы недавно были на FB? Вы видите, как другие люди занимаются крутыми вещами: путешествуют по миру, создают изобретения, а я делаю что-то не такое уж крутое - ну, мы используем интерфейс IComparable.

  • Мы сравниваем текущий экземпляр (вас самих) с другим объектом (кем-то еще) того же типа (человеком).

А как насчет класса Comparer?

Класс Comparer - это абстрактный базовый класс, реализующий интерфейс IComparer. Чтобы иметь конкретную реализацию, вы должны быть производным от этого класса. в любом случае Microsoft рекомендует ДЕЙСТВИТЕЛЬНО использовать класс Comparer, а не реализовывать интерфейс IComparer:

Мы рекомендуем унаследовать от класса Comparer вместо реализации интерфейса IComparer, потому что класс Comparer предоставляет явную реализацию интерфейса метода IComparer.Compare и свойства Default, которое получает компаратор по умолчанию для объекта.

Резюме

  • IComparer - сопоставьте две вещи и сравните.
  • IComparable - сравните себя с другими на FB.

Надеюсь, рассказы помогут вам вспомнить.

BKSpurgeon
источник
1
Мне нравится ваш способ иллюстрации ключевой концепции. Было бы лучше, если бы вы включили в этот конкурс класс Comparer (T). Даже это не входит в вопрос. :)
Кевман
4

Как говорили другие, они не делают то же самое.

В любом случае сейчас я не использую IComparer. Зачем мне? Его ответственность (внешняя сущность, используемая для сравнения двух объектов) может быть решена гораздо более четко с помощью лямбда-выражения, аналогично тому, как работает большинство методов LINQ. Напишите короткую лямбду, которая принимает объекты для сравнения в качестве аргументов и возвращает логическое значение. И если объект определяет свою собственную внутреннюю операцию сравнения, вместо этого он может реализовать IComparable.

Jalf
источник
1
-1: возвращение bool не эквивалентно IComparer. IComparer возвращает значение, которое может быть меньше нуля / ноль / больше нуля и обычно используется для сортировки.
Джо
И когда это то, что вам нужно, вы вместо этого возвращаете int (или, еще лучше, enum). Это действительно большое дело?
jalf
2
Вы даже можете вернуть bool, поскольку для сортировки последовательности вам нужна только операция «меньше».
jalf
реализация IComparer должна быть определена только один раз, если вам нужно использовать логику сортировки в большем количестве мест, тогда лямбда-выражение нужно будет писать несколько раз.
oɔɯǝɹ 06
oɔɯǝɹ - Затем вы можете сохранить ссылку на делегат, который был написан как лямбда-выражение, также повторно используйте его.
jpierson
3

IComparable говорит, что объект можно сравнивать с другим. IComparer - это объект, который может сравнивать любые два элемента.

Нил Барнуэлл
источник
2

IComparer - это интерфейс, который используется для сортировки массива, этот интерфейс заставит класс реализовать метод Compare (T x, T y), который будет сравнивать два объекта. Экземпляр класса, который реализовал этот интерфейс, используется при сортировке массива.

IComparable - это интерфейс, реализованный в типе, который должен сравнивать два объекта одного типа. Этот сопоставимый интерфейс заставит класс реализовать следующий метод CompareTo (T obj)

IEqualityComparer - это интерфейс, который используется для поиска объекта, независимо от того, равен он или нет. Теперь мы увидим это в примере, где нам нужно найти Отличительные черты объекта в коллекции. Этот интерфейс реализует метод Equals (T obj1, T obj2)

Теперь мы возьмем пример, у нас есть класс Employee, на основе этого класса мы должны создать коллекцию. Теперь у нас есть следующие требования.

Отсортируйте массив с помощью класса Array 2. Нужна коллекция с помощью Linq: удалить дубликат, упорядочить по возрастанию к меньшему, удалить один идентификатор сотрудника

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

public enum SortType
{
    ByID,
    BySalary
}

открытый класс EmployeeIdSorter: IComparer {public int Compare (Employee x, Employee y) {if (x.Id <y.Id) return 1; иначе, если (x.Id> y.Id) return -1; иначе вернуть 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;
        }
    }

Для получения дополнительной информации см. Ниже http://dotnetvisio.blogspot.in/2015/12/usage-of-icomparer-icomparable-and.html

Раджеш Дж.
источник