Cuándo usar IComparable <T> Vs. IComparer <T>

Respuestas:

96

Bueno, no son exactamente lo mismo que IComparer<T>se implementa en un tipo que es capaz de comparar dos objetos diferentes, mientras que IComparable<T>se implementa en tipos que pueden compararse con otras instancias del mismo tipo.

Tiendo a usarlo IComparable<T>para momentos en los que necesito saber cómo se relaciona otra instancia con la thisinstancia. IComparer<T>es útil para clasificar colecciones como los IComparer<T>soportes fuera de la comparación.

Andrew Hare
fuente
9
IComparer <T> también le permite tener una clase para cada tipo de clasificación que desee. Ejemplo; PersonLastFirstNameComparer, PersonFirstLastNameComparer o PersonAgeComparer.
Eric Schneider
¿Existe una forma fácil de recordarlos? Tiendo a tener que buscarlo cada vez.
amadib
59
@amadib piensa IComparablecomo soy comparable . lo que significa que puedo compararme con otra cosa. Y IComparercomo soy un comparador, simplemente comparo, lo que significa que comparo algunas cosas.
Nawfal
@newfal Deberías haber puesto esto como respuesta. Creo que es la mejor explicación aquí.
Gene S
42

Úselo IComparable<T>cuando la clase tenga una comparación intrínseca.

Úselo IComparer<T>cuando desee un método de comparación diferente a la comparación intrínseca de la clase, si tiene uno.

yfeldblum
fuente
28

Depende de la entidad. Por ejemplo, siguiendo para una clase como "Estudiante", tendrá sentido tener IComparable basado en Nombre.

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

Pero si un profesor 'A' quiere comparar a los estudiantes en función de MathScore, y el profesor 'B' quiere comparar a los estudiantes en función de EnglishScore. Será una buena idea implementar IComparer por separado. (Más como un patrón de estrategia)

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
fuente
Haga que el método de comparación sea estático para facilitar su uso.
Ene
9

Todo depende de si tu tipo es mutable o no. Usted debe solamente aplicar IComparable de tipos no mutables. Tenga en cuenta que si implementa IComparable, debe anular Equals, junto con los operadores ==,! =, <Y> (consulte la advertencia de análisis de código CA1036).

Citando a Dave G de esta publicación de blog :

Pero la respuesta correcta es implementar IComparer en lugar de IComparable si sus objetos son mutables y pasar una instancia de IComparer a las funciones de clasificación cuando sea necesario.

Dado que IComparer es solo un objeto desechable que se utiliza para clasificar en ese momento, su objeto puede tener cualquier semántica mutable que desee. Además, no requiere ni sugiere el uso de Equals, GetHashCode o ==; puede definirlo como desee.

Finalmente, puede definir múltiples IComparer para su tipo para clasificar en diferentes campos o con diferentes reglas. Esto es mucho más flexible que quedarse atascado con una definición.

En resumen: use IComparable para tipos de valor e IComparer para tipos de referencia.

Sr. Bungle
fuente
6

Explicación simple a través de una historia

Baloncesto de secundaria. Es una selección de patio de la escuela para los equipos. Quiero tener a las personas más altas / mejores / más rápidas en mi equipo. ¿Qué debo hacer?

Interfaz IComparer : compare dos personas por separado

  • Esto me permite comparar a dos chicos en fila ... eso es básicamente todo. Fred vs John .......... los arrojo a una clase concreta que implementa la interfaz. Compare(Fred, John)y escupe quién es mejor.

¿Qué pasa con IComparable? - Compárate con alguien más

¿Has estado en FB recientemente? Ves a otras personas haciendo cosas interesantes: viajar por el mundo, crear inventos, mientras yo hago algo que no es tan genial, bueno, lo que estamos haciendo es utilizar la interfaz IComparable.

  • Estamos comparando la instancia actual (usted mismo) con otro objeto (alguien más) que es del mismo tipo (persona).

¿Qué pasa con la clase Comparer?

La clase Comparer es una clase base abstracta que implementa la interfaz IComparer. Debes derivar de esta clase para tener una implementación concreta. de todos modos, Microsoft recomienda que use la clase Comparer en lugar de implementar la interfaz IComparer:

Recomendamos que se derive de la clase Comparer en lugar de implementar la interfaz IComparer, porque la clase Comparer proporciona una implementación de interfaz explícita del método IComparer.Compare y la propiedad Default que obtiene el comparador predeterminado para el objeto.

Resumen

  • IComparer: alinee dos cosas y compare.
  • IComparable: compárese con otros en FB.

Espero que las historias te ayuden a recordar.

BKSpurgeon
fuente
1
Me gusta tu forma de ilustrar el concepto clave. Podría ser mejor si incluye la clase Comparer (T) en este concurso. Incluso no está incluido en la pregunta. :)
Kevman
4

Como han dicho otros, no hacen lo mismo.

En cualquier caso, estos días no suelo usar IComparer. ¿Por qué habría? Su responsabilidad (una entidad externa utilizada para comparar dos objetos) se puede manejar de manera mucho más limpia con una expresión lambda, similar a cómo funcionan la mayoría de los métodos de LINQ. Escriba una lambda rápida que tome los objetos para compararlos como argumentos y devuelva un bool. Y si el objeto define su propia operación de comparación intrínseca, puede implementar IComparable en su lugar.

jalf
fuente
1
-1: devolver un bool no es equivalente a IComparer. IComparer devuelve un valor que puede ser menor que cero / cero / mayor que cero y generalmente se usa para ordenar.
Joe
Y cuando eso es lo que necesita, devuelve un int (o mejor aún, una enumeración) en su lugar. ¿Es eso realmente un gran problema?
jalf
2
Incluso puede devolver un bool, ya que menos de es la única operación que necesita para ordenar una secuencia.
jalf
una implementación de IComparer solo necesita definirse una vez, si necesita usar la lógica de clasificación en más lugares, entonces la expresión lambda deberá escribirse más veces.
2010
oɔɯǝɹ - Entonces puede almacenar una referencia al delegado que se escribió como una expresión lambda y reutilizarla también.
jpierson
3

IComparable dice que un objeto se puede comparar con otro. IComparer es un objeto que puede comparar dos elementos cualesquiera.

Neil Barnwell
fuente
2

IComparer es una interfaz que se utiliza para ordenar el Array, esta interfaz obligará a la clase a implementar el método Compare (T x, T y), que comparará los dos objetos. La instancia de la clase que implementó esta interfaz se usa en la clasificación del Array.

IComparable es una interfaz implementada en el tipo que necesita comparar los dos objetos del mismo tipo. Esta interfaz comparable obligará a la clase a implementar el siguiente método CompareTo (T obj)

IEqualityComparer es una interfaz que se usa para encontrar el objeto, sea igual o no. Ahora veremos esto en una muestra donde tenemos que encontrar el Distinto de un Objeto en una colección. Esta interfaz implementará un método Equals (T obj1, T obj2)

Ahora tomamos un ejemplo, tenemos una clase de empleado, en base a esta clase tenemos que crear una colección. Ahora tenemos los siguientes requisitos.

Ordene la matriz usando la clase de matriz 2. Necesita una colección usando Linq: eliminar el duplicado, ordenar de mayor a menor, eliminar una identificación de empleado

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

public enum SortType
{
    ByID,
    BySalary
}

clase pública EmployeeIdSorter: IComparer {public int Compare (Empleado x, Empleado y) {if (x.Id <y.Id) return 1; else if (x.Id> y.Id) return -1; de lo contrario, devuelve 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 obtener más información, consulte a continuación http://dotnetvisio.blogspot.in/2015/12/usage-of-icomparer-icomparable-and.html

Rajesh G
fuente