В чем разница между интерфейсами IComparable и IEquatable?


Ответы:


189

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 страниц для целей IComparable)
Damien_The_Unbeliever 09

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

2
@Konrad Rudolph: А что насчет класса "ScheduledEvent", который должен делать "что-то" в определенное время? Семантика типа подразумевала бы очень сильное естественное семантическое упорядочение, основанное на том, когда действие должно было произойти, но можно легко иметь разные события, происходящие одновременно. Можно было бы потребовать использования указанного вручную компаратора IComparer, но я бы сказал, что было бы удобнее иметь встроенный в класс компаратор.
supercat

4
@supercat Удобство важно, но это еще не все. Правильность (например, логическая последовательность) более важна, и система статических типов является важным инструментом для проверки этой логической непротиворечивости. Нарушая документированный контракт реализуемых вами интерфейсов, вы подрываете систему типов. Это не очень хорошая идея, и я никогда не рекомендовал бы его. Для таких ситуаций используйте внешний компаратор.
Конрад Рудольф

7

Как указано на странице MSDN для IEquatable :

Интерфейс IComparable определяет CompareToметод, который определяет порядок сортировки экземпляров реализующего типа. Интерфейс IEquatable определяет Equalsметод, который определяет равенство экземпляров реализующего типа.

Equals vs. CompareTo


4

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

IEquatable <T> определяет обобщенный метод, который можно использовать для определения равенства.


Допустим, у вас есть класс 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 };

Для сортировки этих объектов вы можете использовать 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.