¿Cuál es la diferencia entre las interfaces IComparable e IEquatable?


Respuestas:


188

IEquatable comprueba si dos objetos son iguales.

IComparable impone un ordenamiento total a los objetos que se comparan.

Por ejemplo, IEquatablele diría que 5 no es igual a 7. IComparablele diría que 5 viene antes que 7.



10

Además de la respuesta de Greg D:

Puede implementar IComparablesin implementar IEquatablepara una clase donde un orden parcial tiene sentido, y donde definitivamente quiere que el consumidor infiera que solo porque CompareTo()devuelve cero, esto no implica que los objetos sean iguales (para cualquier otra cosa que no sea la clasificación).


10
Eso suena mucho más a un comparador de casos especiales que a un objeto que se implementa IComparablecorrectamente. Se puede llegar a un ejemplo significativo, donde CompareTo(…) == 0no no implica la igualdad? Ciertamente no puedo. De hecho, el contrato de interfaz (según MSDN) requiere que eso CompareTo(…) == 0implique igualdad. Para decirlo sin rodeos, en un caso como el suyo, use un Comparatorobjeto especial , no lo implemente IComparable.
Konrad Rudolph

2
@Konrad: indiqué varias advertencias: que el tipo no implementa IEquatable (por lo que, obviamente, el creador no quiere incluir una prueba de igualdad), y que los resultados de CompareTo se usan para clasificar, no para evaluar la igualdad. También te preguntas qué igualdad es relevante (referencia, valor, ignorando atributos "arbitrarios": un libro azul de 500 páginas de largo puede ser "igual" a un libro rojo de 500 páginas de largo, a los efectos de IComparable)
Damien_The_Unbeliever

4
Su última oración es incorrecta, y este es el error particular que quería señalar: IComparablees totalmente inapropiado aquí. Lo que tiene es un pedido muy particular que solo se aplica en una situación especial. Para tales situaciones, implementar un general IComparableestá mal. Para eso IComparerestán las s. Por ejemplo, no se puede ordenar a las personas de manera significativa. Pero se pueden ordenar según su salario, la talla de sus zapatos, el número de sus pecas o su peso. Por lo tanto, implementaríamos diferentes IComparers para todos estos casos.
Konrad Rudolph

2
@Konrad Rudolph: ¿Qué pasa con algo como una clase "ScheduledEvent", que se supone que hace "algo" en algún momento en particular? La semántica del tipo implicaría un ordenamiento semántico natural muy fuerte basado en cuándo se suponía que tenía lugar la acción, pero uno podría tener fácilmente diferentes eventos que ocurren al mismo tiempo. Se podría requerir el uso de un IComparer especificado manualmente, pero yo diría que tener un comparador integrado en la clase sería más conveniente.
supercat

4
@supercat La comodidad es importante, pero no lo es todo. La corrección (como en la coherencia lógica) es más importante y el sistema de tipos estáticos es una herramienta importante para verificar esta coherencia lógica. Al violar el contrato documentado de interfaces que implementa, está subvirtiendo el sistema de tipos. Esta no es una buena idea y nunca la recomendaría. Utilice un comparador externo para tales situaciones.
Konrad Rudolph

7

Como se indica en la página de MSDN para IEquatable :

La interfaz IComparable define el CompareTométodo, que determina el orden de clasificación de las instancias del tipo de implementación. La interfaz IEquatable define el Equalsmétodo, que determina la igualdad de instancias del tipo de implementación.

Equals vs. CompareTo


2

IComparable <T> define un método de comparación específico de tipo que se puede utilizar para ordenar u ordenar objetos.

IEquatable <T> define un método generalizado que se puede utilizar para implementar para determinar la igualdad.


Digamos que tienes clase Person

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Person p1 = new Person() { Name = "Person 1", Age = 34 };
Person p2 = new Person() { Name = "Person 2", Age = 31 };
Person p3 = new Person() { Name = "Person 3", Age = 33 };
Person p4 = new Person() { Name = "Person 4", Age = 26 };

List<Person> people = new List<Person> { p1, p2, p3, p4 };

Para ordenar estos objetos puede utilizar people.Sort(); .

Pero esto arrojará una excepción.

ingrese la descripción de la imagen aquí

Framework no sabe cómo ordenar estos objetos. Necesita decir cómo ordenar la implementación de la IComparableinterfaz.

public class Person : IComparable
{
    public string Name { get; set; }
    public int Age { get; set; }

    public int CompareTo(object obj)
    {
        Person otherPerson = obj as Person;
        if (otherPerson == null)
        {
            throw new ArgumentNullException();
        }
        else
        {
            return Age.CompareTo(otherPerson.Age);
        }
    }
}

Esto ordenará la matriz correctamente con el Sort()método.


A continuación, para comparar dos objetos puede utilizar el Equals()método.

var newPerson = new Person() { Name = "Person 1", Age = 34 };
var newPersonIsPerson1 = newPerson.Equals(p1);

Esto regresaráfalse porque el Equalsmétodo no sabe cómo comparar dos objetos. Por lo tanto, debe implementar la IEquatableinterfaz y decirle al marco cómo hacer la comparación. Ampliando el ejemplo anterior, se verá así.

public class Person : IComparable, IEquatable<Person>
{
    //Some code hidden

    public bool Equals(Person other)
    {
        if (Age == other.Age && Name == other.Name)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

1
Gracias por esta gran explicación. Pregunta: ¿por qué IEquatableutiliza un genérico <Person>y IComparableno?
veuncent
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.