Является ли интерфейс IComparable устаревшим / «вредным»?


11

IComparable работает только в одну сторону

Допустим, у вас есть Employeeкласс. В одном представлении вы хотите показать все Employeesотсортированные по имени - в другом по адресу. Как вы собираетесь достичь этого? Не с IComparable, по крайней мере, никаким идиоматическим способом.

IComparable имеет логику в неправильном месте

Интерфейс используется при вызове .Sort(). В представлении, отображающем Customerотсортированный по имени, вообще нет кода, который бы указывал, как он будет сортироваться.
С другой стороны, Customerкласс предполагает, как он будет использоваться - в этом случае он будет использоваться в списке, отсортированном по именам.

IComparable используется неявно

По сравнению с альтернативами очень трудно увидеть, где используется логика сравнения - или вообще. Предполагая вашу стандартную среду разработки и начиная с Customerкласса, мне придется

  1. Поиск всех ссылок на Customer
  2. Найдите те ссылки, которые используются в списке
  3. Проверьте, .Sort()вызывали ли эти списки их

Что еще хуже, если вы удалите IComparableреализацию, которая все еще используется, вы не получите никаких ошибок или предупреждений. Единственное, что вы получите, - это неправильное поведение во всех местах, которые были слишком неясны для вас.

Эти проблемы объединены, плюс меняющиеся требования

Сама причина, по которой я начал думать об этом, заключается в том, что для меня это пошло не так. Я успешно использую IComparableв своем приложении в течение 2 лет. Теперь требования изменились, и вещь должна быть отсортирована двумя разными способами. Заметили, что неинтересно проходить шаги, описанные в предыдущем разделе.

Вопрос

Эти проблемы заставляют меня думать, IComparableчто я уступаю IComparerили .OrderBy(), до такой степени, что не вижу ни одного действительного варианта использования, который не будет лучше обслуживаться альтернативами.
Всегда ли лучше использовать IComparerили LINQ, или я не вижу здесь преимуществ / вариантов использования?


2
Ваше новое требование "сортировать двумя разными способами" - это красная сельдь. Чтобы решить эту проблему, все, что вам нужно сделать, это передать другой компаратор в функцию сортировки.
— Роберт Харви

@RobertHarvey Тогда ты больше не будешь использовать IComparable, что подтверждает мою точку зрения.
— Р. Шмитц

Не забывайте, что если вы используете SortedXXXколлекции, они либо требуют, чтобы сохраненные элементы были, IComparableлибо чтобы они были IComparerпредоставлены. Также обратите внимание, что тривиально изменить порядок естественной сортировки с помощью одного компаратора и заставить его работать со всеми IComparableобъектами.
— Берин Лорич

2
Неважно, что есть два разных интерфейса. IComparableсчитается механизмом сравнения по умолчанию . IComparerиспользуется, когда вы хотите переопределить механизм сравнения по умолчанию.
— Роберт Харви

Ответы:


14

IComparableимеет ограничения, которые вы упомянули, это правильно. Это интерфейс, который уже был доступен в .NET Framework 1.0, где эти функциональные альтернативы и Linq были недоступны. Так что да, это можно рассматривать как устаревший элемент инфраструктуры, который в основном сохраняется для обратной совместимости.

Однако для многих простых структур данных один из способов сортировки, вероятно, достаточно или естественен. В этих случаях наличие одного канонического места для реализации отношения порядка все еще является хорошим способом сохранить код СУХИМ, вместо того, чтобы всегда повторять одну и ту же логику при каждом вызове OrderByповсюду.

Как вы писали, вы «счастливо используете IComparable в своем приложении уже 2 года», так что, как мне кажется, он долгое время служил вам хорошо. Когда вам теперь нужно проверять, изменять и тестировать все вызовы Sort, это также может быть признаком того, что вы выполняете одну и ту же логику сортировки во многих местах, что не является ошибкой IComparable. Так что это может быть поводом для централизации большей части этой логики в одном месте, делая ваш код более СУХИМЫМ.


Хороший вопрос о простых структурах данных. Однако последний абзац не имеет для меня 100% смысла. Если бы я не использовал IComparable, весь существующий код сортировки остался бы нетронутым в их соответствующих представлениях, в то время как я бы добавил только новый код сортировки для нового представления.
— Р. Шмитц

@ R.Schmitz Сработала бы уже существующая сортировка без IComparableнаписанной вами реализации?
— Роберт Харви

3
@ R.Schmitz: Конечно, но теперь вы всегда готовы предоставить компаратор (если, конечно, вы не используете OrderBy). С помощью IComparableвы получаете реализацию по умолчанию бесплатно, а иногда вам даже не нужно писать эту реализацию.
— Роберт Харви

2
@ R.Schmitz: Ваш последний комментарий хорошо подводит итог. Я бы пошел немного дальше, хотя. Предположим, у вас есть числовой тип, как BigInteger. Если бы он не реализовывал операторы / интерфейсы сравнения, как бы вы реализовали IComparer самостоятельно ? Вам понадобится доступ к внутренним структурам данных, чтобы сделать это эффективно или вообще. Предположим, у вас есть такой тип, как Customer; общедоступные свойства, по которым вы хотите отсортировать , имеют компараторы. Для меня в этом разница: реализовать, IComparable<T>если было бы неразумно ожидать, что вызывающая сторона будет реализовывать компаратор.
— Эрик Липперт

1
If I hadn't used IComparable, all the pre-existing sorting code would have been left untouched in their respective views, while I'd only add new sorting code for the new view.Просто потому что IComparableбыл лучше в то время это решение , не означает, что это лучшее решение сегодня . Ваш первый комментарий здесь подразумевает, что «это сопоставимо или ничего», что не соответствует действительности, проблема могла быть решена различными способами. Приложения могут увеличиваться в размере / масштабе, а вещи, которые раньше выглядели подходящими, могут не соответствовать растущим требованиям приложения.
— Флэттер

1

Я согласен с вашими чувствами по поводу IComparable

Просто посмотрите на замечания по Array.Sort()

  • Каждый элемент массива должен реализовывать IComparable интерфейс для возможности сравнения с любым другим элементом массива. (или исключение выдается)
  • Если сортировка не была успешно завершена, результаты не определены.

Мы, вероятно, никогда не будем сейчас мотивации, однако! рассматриватьobject.Equals() метод для каждого объекта, который позволяет сравнивать объекты друг с другом, чтобы увидеть, являются ли они «одинаковыми»

У вас это уже есть, но вам нужно было добавить, что Array.Sort()вы можете добавитьobject.Compare(object)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.