Когда использовать IComparable <T>Vs. IComparer <T> - PullRequest
98 голосов
/ 11 февраля 2009

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

Ответы [ 8 ]

92 голосов
/ 11 февраля 2009

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

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

42 голосов
/ 11 февраля 2009

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

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

27 голосов
/ 15 марта 2011

Это зависит от сущности. Например, для класса, подобного «Student», будет иметь смысл иметь IComparable на основе 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);  
    }
}

Но если учитель "А" хочет сравнить учащихся на основе 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;
    }
}
9 голосов
/ 18 октября 2010

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

Цитата Дэйва Дж из этого блога :

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

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

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

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

6 голосов
/ 05 февраля 2016

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

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

Интерфейс IComparer - Сравнение двух человек, отдельных людей

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

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

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

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

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

Класс Comparer - это абстрактный базовый класс, который реализует интерфейс IComparer. Вы должны наследовать от этого класса, чтобы иметь конкретную реализацию. В любом случае, Microsoft рекомендует использовать класс Comparer, а не реализовывать интерфейс IComparer:

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

Краткое описание

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

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

4 голосов
/ 11 февраля 2009

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

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

3 голосов
/ 11 февраля 2009

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

2 голосов
/ 09 сентября 2016

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

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

IEqualityComparer - это интерфейс, который используется для поиска объекта независимо от того, равен он или нет. Теперь мы увидим это в примере, где нам нужно найти отличительные признаки объекта в коллекции. Этот интерфейс будет реализовывать метод Равен (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 (Сотрудник x, Сотрудник y) { if (x.Id y.Id) возврат -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

...