Чи застарілий / "шкідливий" інтерфейс 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.