Чи застарілий / "шкідливий" інтерфейс IComparable?


11

IComparable працює лише одним способом

Скажімо, у вас Employeeклас. З одного виду, ви хочете показати всі Employeesвідсортовані за назвою - в іншому за адресою. Як ти збираєшся цього досягти? Не з IComparable, принаймні, не в жодному ідіоматичному вигляді.

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

Інтерфейс використовується при виклику .Sort(). У поданні, яке відображає Customerсортування за назвою, взагалі немає коду, який би вказував, як він буде сортований.
З іншого боку, Customerклас припускає, як він буде використовуватися - у цьому випадку він буде використовуватися у списку, відсортованому за іменами.

IComparable використовується неявно

У порівнянні з альтернативами, дуже важко зрозуміти, де використовується логіка порівняння - чи взагалі. Припускаючи ваш стандартний IDE і починаючи з 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 були недоступні. Так, так, можна побачити це як застарілий рамковий елемент, який в основному зберігається для зворотної сумісності.

Однак для багатьох простих структур даних одного способу сортування, ймовірно, достатньо чи природного. У цих випадках наявність одного канонічного місця для реалізації відносин замовлення все ще є хорошим способом зберегти код DRY, замість того, щоб завжди повторювати ту саму логіку в кожному дзвінку в OrderByусьому місці.

Як ви вже писали, ви "із задоволенням використовуєте IComparable у вашій заявці вже 2 роки", тому мені здається, що він вам довго слугував. Коли вам доведеться перевірити, змінити і протестувати всі дзвінки Sort, це також може бути ознакою того, що ви робили таку ж логіку сортування у багатьох місцях, що не є виною IComparable. Тож це може бути приводом централізувати більше цієї логіки в одному місці, зробивши ваш код більш ДУХОМ.


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

@ R.Schmitz Чи правильно працювали попередні сорти без IComparableреалізації, яку ви написали?
— Роберт Харві

3
@ R.Schmitz: Звичайно, але тепер ви зобов’язані завжди надавати компаратор (якщо, звичайно, не використовуєте OrderBy). З IComparable, ви отримуєте реалізацію за замовчуванням безкоштовно, а іноді навіть не потрібно писати цю реалізацію.
— Роберт Харві

2
@ R.Schmitz: Ваш останній коментар там добре підсумовує. Я хотів би піти трохи далі. Припустимо, у вас числовий тип типу BigInteger. Якби він не реалізував оператори / інтерфейси порівняння, як би ви навіть самі реалізували IComparer ? Вам знадобиться доступ до внутрішніх структур даних, щоб це зробити ефективно або взагалі. Припустимо, у вас є такий тип, як Клієнт; у загальнодоступних об'єктах, які ви хочете сортувати , є порівняльники. Для мене це відмінність: реалізуйте, 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був краще рішення в той час , не означає , що це краще рішення сьогодні . Ваш перший коментар тут означає, що "це непорівнянно чи нічого", що не відповідає дійсності, проблему можна було вирішити різними способами. Програми можуть збільшуватися в розмірах / масштабах, і речі, які раніше виглядали підходящими, можуть не встигати відповідати зростаючим вимогам програми.
— Flater

1

Я згоден з вашими настроями щодо IComparable

Просто подивіться на зауваження далі Array.Sort()

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

Напевно, ми ніколи не будемо мотивації, однак! розглянути object.Equals()метод кожного об'єкта, який дозволяє порівнювати об'єкти між собою, щоб побачити, чи вони "однакові"

У вас це вже є, але ви отримали завдання додати Array.Sort()його, можливо, захочете додатиobject.Compare(object)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.