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

Respostas:

96

Bem, eles não são exatamente a mesma coisa que IComparer<T>são implementados em um tipo que é capaz de comparar dois objetos diferentes, enquanto IComparable<T>são implementados em tipos que são capazes de se comparar com outras instâncias do mesmo tipo.

Costumo usar IComparable<T>quando preciso saber como outra instância se relaciona com a thisinstância. IComparer<T>é útil para classificar coleções IComparer<T>fora da comparação.

Andrew Hare
fonte
9
IComparer <T> também permite que você tenha uma classe para cada tipo de tipo que você deseja. Exemplo; PersonLastFirstNameComparer, PersonFirstLastNameComparer ou PersonAgeComparer.
Eric Schneider,
Existe uma maneira fácil de lembrar deles? Costumo ter que pesquisar todas as vezes.
amadib
59
@amadib pense IComparablecomo sou comparável . o que significa que posso ser comparado a outra coisa. E lido IComparercomo um comparador, simplesmente comparo, o que significa que comparo algumas coisas.
nawfal
@newfal Você deveria ter colocado isso como uma resposta. Acho que é a melhor explicação aqui.
Gene S
42

Use IComparable<T>quando a classe tiver uma comparação intrínseca.

Use IComparer<T>quando quiser um método de comparação diferente da comparação intrínseca da classe, se houver.

Yfeldblum
fonte
28

Depende da entidade. Por exemplo, seguindo para uma classe como "Aluno", fará sentido ter IComparável com base no 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);  
    }
}

Mas se um professor 'A' deseja comparar alunos com base no MathScore, e o professor 'B' deseja comparar alunos com base no EnglishScore. Será uma boa ideia implementar IComparer separadamente. (Mais como um padrão de estratégia)

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
fonte
Torne o método Compare estático para facilitar o uso.
Jan
9

Tudo depende se o seu tipo é mutável ou não. Você deve implementar IComparable em tipos não mutáveis. Observe que, se você implementar IComparable, deverá substituir Equals, juntamente com os operadores ==,! =, <E> (consulte o aviso de Análise de Código CA1036).

Citando Dave G nesta postagem do blog :

Mas a resposta correta é implementar IComparer em vez de IComparable se seus objetos forem mutáveis ​​e passar uma instância do IComparer para funções de classificação quando necessário.

Visto que o IComparer é apenas um objeto descartável usado para classificação naquele ponto no tempo, seu objeto pode ter qualquer semântica mutável que você desejar. Além disso, não exige nem sugere o uso de Equals, GetHashCode ou == - você é livre para defini-lo da maneira que quiser.

Finalmente, você pode definir vários IComparers para seu tipo para classificação em campos diferentes ou com regras diferentes. Isso é muito mais flexível do que ficar preso a uma definição.

Resumindo: Use IComparable para tipos de valor e IComparer para tipos de referência.

Sr. Bungle
fonte
6

Explicação simples por meio de uma história

Basquete colegial. É uma escolha de pátio de escola para as equipes. Eu quero ter o pessoal mais alto / melhor / mais rápido da minha equipe. O que eu faço?

Interface IComparer - compare duas pessoas, diferentes pessoas

  • Isso me permite comparar quaisquer dois caras alinhados ......... é basicamente isso. Fred vs John .......... eu os coloco em uma classe concreta que implementa a interface. Compare(Fred, John)e expõe quem é melhor.

Que tal IComparable? - Compare-se com outra pessoa

Você esteve no FB recentemente? Você vê outras pessoas fazendo coisas legais: viajando pelo mundo, criando invenções, enquanto eu faço algo não tão legal - bem, o que estamos fazendo é usando a interface IComparable.

  • Estamos comparando a instância atual (você) com outro objeto (outra pessoa) que é do mesmo tipo (pessoa).

E a classe comparadora?

A classe Comparer é uma classe base abstrata que implementa a interface IComparer. Você deve derivar desta classe para ter uma implementação concreta. de qualquer forma, a Microsoft recomenda que você USE a classe Comparer em vez de implementar a interface IComparer:

Recomendamos que você derive da classe Comparer em vez de implementar a interface IComparer, porque a classe Comparer fornece uma implementação de interface explícita do método IComparer.Compare e da propriedade Default que obtém o comparador padrão para o objeto.

Resumo

  • IComparer - alinhe duas coisas e compare.
  • IComparable - compare-se com outros no FB.

Espero que as histórias ajudem você a se lembrar.

BKSpurgeon
fonte
1
Gosto da sua maneira de ilustrar o conceito-chave. Poderia ser melhor se você incluir a classe Comparer (T) neste concurso. Mesmo não sendo incluído na pergunta. :)
Kevman
4

Como outros já disseram, eles não fazem a mesma coisa.

De qualquer forma, hoje em dia não costumo usar o IComparer. Por que eu deveria? Sua responsabilidade (uma entidade externa usada para comparar dois objetos) pode ser tratada de forma muito mais clara com uma expressão lambda, semelhante a como a maioria dos métodos do LINQ funcionam. Escreva um lambda rápido que leva os objetos para comparar como argumentos e retorna um bool. E se o objeto definir sua própria operação de comparação intrínseca, ele pode implementar IComparable.

Jalf
fonte
1
-1: retornar um bool não é equivalente a IComparer. IComparer retorna um valor que pode ser menor que zero / zero / maior que zero e é normalmente usado para classificação.
Joe
E quando é disso que você precisa, você retorna um int (ou melhor ainda, um enum). Isso é realmente um grande negócio?
jalf
2
Você pode até retornar um bool, já que less than é a única operação necessária para classificar uma sequência.
jalf
uma implementação IComparer só precisa ser definida uma vez, se você precisar usar a lógica de classificação em mais lugares, a expressão lambda precisará ser escrita mais vezes.
2010
oɔɯǝɹ - Então você pode armazenar uma referência ao delegado que foi escrita como uma expressão lambda e reutilizá-la também.
jpierson
3

IComparable diz que um objeto pode ser comparado a outro. IComparer é um objeto que pode comparar dois itens quaisquer.

Neil Barnwell
fonte
2

IComparer é uma interface que é usada para ordenar o Array, esta interface forçará a classe a implementar o método Compare (T x, T y), que irá comparar os dois objetos. A instância da classe que implementou esta interface é usada na classificação do Array.

IComparable é uma interface implementada no tipo que precisa comparar os dois objetos do mesmo tipo. Esta interface comparável forçará a classe a implementar o seguinte método CompareTo (T obj)

IEqualityComparer é uma interface que é usada para encontrar o objeto seja igual ou não, agora veremos isso em um exemplo onde temos que encontrar o distinto de um objeto em uma coleção. Esta interface implementará um método Equals (T obj1, T obj2)

Agora vamos dar um exemplo, temos uma classe Employee, com base nesta classe temos que criar uma coleção. Agora temos os seguintes requisitos.

Classifique o Array usando a classe Array 2. Precisa de uma coleção usando o Linq: Remova a duplicata, ordene de cima para baixo, remova um id de funcionário

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; senão if (x.Id> y.Id) return -1; senão retorne 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;
        }
    }

Para mais informações, consulte abaixo http://dotnetvisio.blogspot.in/2015/12/usage-of-icomparer-icomparable-and.html

Rajesh G
fonte