У чому різниця між інтерфейсами IComparable та IEquatable?


Відповіді:


188

IEquatable перевіряє, чи два об'єкти рівні.

IComparable накладає повне впорядкування об’єктів, що порівнюються.

Наприклад, IEquatableсказали б вам, що 5 не дорівнює 7. IComparableсказали б, що 5 приходить до 7.



10

На додаток до відповіді Грега Д.

Ви можете реалізовувати, IComparableне застосовуючи IEquatableдля класу, де часткове замовлення має сенс і де ви точно хочете, щоб споживач міг зробити висновок про те, що лише тому, що CompareTo()повертає нуль, це не означає, що об'єкти рівні (для будь-яких цілей, крім сортування).


10
Це звучить набагато більше як порівняння в окремому випадку, ніж як об’єкт, який реалізується IComparableналежним чином. Можете чи ви придумати змістовний прикладом , де CompareTo(…) == 0це НЕ має на увазі рівність? Я точно не можу. Насправді, інтерфейсний контракт (згідно з MSDN) вимагає, що CompareTo(…) == 0передбачає рівність. Якщо прямо сказати, у такому випадку, як ваш, використовуйте спеціальний Comparatorоб’єкт, не реалізовуйте IComparable.
Конрад Рудольф

2
@Konrad - Я вказав кілька застережень - що тип не реалізує IEquatable (тому очевидно, що джерело не хоче включати тест рівності), і що результати CompareTo використовуються для сортування, а не для оцінки рівності. Ви також стикаєтеся з питаннями, які рівність є релевантною (довідка, значення, ігнорування "довільних" атрибутів - синя книга довжиною 500 сторінок може бути "рівною" червоній книзі довжиною 500 сторінок для цілей, що не порівнянні)
Damien_The_Unbeliever

4
Ваше останнє речення неправильне, і це особлива помилка, на яку я хотів звернути увагу: IComparableтут цілком недоречно. У вас є дуже конкретне замовлення, яке застосовується лише в одній особливій ситуації. Для таких ситуацій реалізація генерала IComparableє неправильним. Для цього IComparerвони є. Наприклад, люди не можуть бути впорядкованими змістовно. Але їх можна замовити відповідно до зарплати, розміру взуття, кількості веснянок або ваги. Отже, ми б застосували різні IComparers для всіх цих випадків.
Конрад Рудольф

2
@ Конрад Рудольф: А як щодо чогось на зразок класу "ScheduledEvent", який повинен робити "щось" у певний час? Семантика типу передбачала б дуже сильне природне семантичне впорядкування, засноване на тому, коли мала відбуватися дія, але можна було легко мати різні події одночасно. Можна вимагати використання вручну визначеного IComparer, але я б припустив, що мати компаратор, вбудований у клас, було б зручніше.
supercat

4
Зручність @supercat важлива, але це не все. Правильність (як і логічна послідовність) важливіша, а система статичного типу - важливий інструмент для перевірки цієї логічної узгодженості. Порушуючи задокументований контракт інтерфейсів, який ви реалізуєте, ви підриваєте систему типів. Це не дуже гарна ідея, і я б ніколи її не рекомендував. Використовуйте зовнішній порівняльник для таких ситуацій.
Конрад Рудольф

7

Як зазначено на сторінці MSDN для IEquatable :

Інтерфейс IComparable визначає CompareToметод, який визначає порядок сортування екземплярів типу реалізації. Інтерфейс IEquatable визначає Equalsметод, який визначає рівність екземплярів типу реалізації.

Equals vs. CompareTo


2

IComparable <T> визначає специфічний для конкретного типу метод порівняння, який можна використовувати для впорядкування або сортування об’єктів.

IEquatable <T> визначає узагальнений метод, який може бути використаний для реалізації для визначення рівності.


Скажімо, у вас є клас Особи

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

Для сортування цих об'єктів ви можете використовувати people.Sort();.

Але це кине виняток.

введіть тут опис зображення

Framework не знає, як сортувати ці об’єкти. Вам потрібно розповісти, як сортувати IComparableінтерфейс реалізації .

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

Це буде сортувати масив належним чином за Sort()методом.


Далі для порівняння двох об’єктів можна використовувати Equals()метод.

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

Це повернеться,false оскільки Equalsметод не знає, як порівняти два об’єкти. Тому вам потрібно реалізувати IEquatableінтерфейс і сказати фреймворку, як зробити порівняння. Продовжуючи попередній приклад, це виглядатиме так.

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
Дякую за це чудове пояснення. Питання: чому IEquatableвикористовується загальний, <Person>а IComparableні?
veuncent
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.