IComparable
działa tylko w jedną stronę
Powiedzmy, że masz Employee
klasę. W jednym widoku chcesz pokazać wszystkie Employees
posortowane według nazwy - w innym według adresu. Jak zamierzasz to osiągnąć? Nie z IComparable
, przynajmniej nie w idiomatyczny sposób.
IComparable
ma logikę w niewłaściwym miejscu
Interfejs jest używany przez wywołanie .Sort()
. W widoku pokazującym Customer
posortowane według nazwy, w ogóle nie ma kodu, który wskazywałby , jak będzie sortowany.
Z drugiej strony Customer
klasa zakłada, w jaki sposób będzie używana - w tym przypadku będzie używana na liście posortowanej według nazw.
IComparable
jest używany niejawnie
W porównaniu z alternatywami bardzo trudno jest zobaczyć, gdzie stosowana jest logika porównawcza - lub w ogóle. Zakładając standardowe IDE i zaczynając od Customer
klasy, będę musiał
- Wyszukaj wszystkie odniesienia do
Customer
- Znajdź odniesienia, które są używane na liście
- Sprawdź, czy te listy kiedykolwiek
.Sort()
do nich dzwoniły
Co gorsza, jeśli usuniesz IComparable
implementację, która jest nadal używana, nie pojawi się błąd ani ostrzeżenie. Jedyne, co dostaniesz, to złe zachowanie we wszystkich miejscach, które były zbyt niejasne, abyś o tym pomyślał.
Te problemy łącznie, a także zmieniające się wymagania
Powodem, dla którego pomyślałem o tym, jest to, że poszło mi nie tak. Z radością korzystam IComparable
z aplikacji od 2 lat. Teraz wymagania się zmieniły i rzecz musi zostać posortowana na 2 różne sposoby. Zauważyłem, że nie jest fajnie przechodzić przez kroki opisane w poprzedniej sekcji.
Pytanie
Te problemy sprawiają, że uważam się IComparable
za gorszy IComparer
lub .OrderBy()
do tego stopnia, że nie widzę żadnego ważnego przypadku użycia, który nie byłby lepiej obsługiwany przez alternatywy.
Czy zawsze lepiej jest używać IComparer
lub LINQ, czy też są zalety / przypadki użycia, których tu nie widzę?
źródło
IComparable
już używać , co wzmacnia mój punkt widzenia.SortedXXX
kolekcji, wymagają one, aby przechowywane elementy byłyIComparable
lub miałyIComparer
zapewnioną. Zauważ też, że odwrócenie naturalnej kolejności sortowania za pomocą jednego urządzenia porównującego i sprawienie, by działała ze wszystkimiIComparable
obiektami , jest banalne .IComparable
jest uważany za domyślny mechanizm porównania.IComparer
jest używany, gdy chcesz zastąpić domyślny mechanizm porównywania.ReverseComparer<T>
: gist.github.com/jackfarrington/078e7af7bc82482aa634Odpowiedzi:
IComparable
ma wspomniane ograniczenia, które są poprawne. Jest to interfejs, który był już dostępny w .NET Framework 1.0, w którym te funkcjonalne alternatywy i Linq nie były dostępne. Tak, można by uznać, że jest to przestarzały element frameworka, który jest głównie przechowywany w celu zachowania kompatybilności wstecznej.Jednak w przypadku wielu prostych struktur danych jeden sposób sortowania jest prawdopodobnie wystarczający lub naturalny. W takich przypadkach posiadanie jednego kanonicznego miejsca do implementacji relacji zamówienia jest nadal dobrym sposobem na zachowanie kodu DRY, zamiast zawsze powtarzania tej samej logiki przy każdym wywołaniu do
OrderBy
całego miejsca.Jak pisałeś, „z radością używasz IComparable w swojej aplikacji od 2 lat”, więc wydaje mi się, że dobrze ci to służyło przez długi czas. Kiedy teraz musisz zweryfikować, zmienić i przetestować wszystkie połączenia z
Sort
, może to być również znak, że robiłeś ten sam rodzaj logiki sortowania w wielu miejscach, co nie jest winąIComparable
. Może to być okazja do scentralizowania większej ilości tej logiki w jednym miejscu, dzięki czemu Twój kod będzie bardziej SUCHY.źródło
IComparable
, cały wcześniej istniejący kod sortowania pozostałby nietknięty w ich odpowiednich widokach, a ja dodałbym tylko nowy kod sortowania dla nowego widoku.IComparable
implementacji, którą napisałeś?IComparable
dostajesz domyślną implementację za darmo, a czasem nawet nie musisz jej pisać.BigInteger
. Jeśli nie zaimplementowałoby operatorów porównania / interfejsów, jak byś sam wdrożył IComparer ? Potrzebny byłby dostęp do wewnętrznych struktur danych, aby zrobić to efektywnie lub wcale. Załóżmy, że masz typ podobny do klienta; obiekty publiczne, które chcesz posortować , mają porównywarki. Dla mnie to jest różnica: implementuj,IComparable<T>
jeśli nierozsądne byłoby oczekiwanie od osoby dzwoniącej implementacji modułu porównującego.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.
Tylko dlatego, żeIComparable
było lepsze rozwiązanie w tym czasie , nie oznacza, że jest to najlepsze rozwiązanie dzisiaj . Twój pierwszy komentarz tutaj sugeruje, że „jest IComparable lub nic”, co nie jest prawdą, problem mógł zostać rozwiązany na wiele różnych sposobów. Aplikacje mogą rosnąć w rozmiarze / skali, a rzeczy, które kiedyś wyglądały odpowiednio, mogą nie być w stanie sprostać rosnącym wymaganiom aplikacji.Zgadzam się z twoimi sentymentami
IComparable
Spójrz tylko na uwagi
Array.Sort()
IComparable
interfejs, aby mógł być porównywany z każdym innym elementem tablicy. (lub zgłoszony wyjątek)Prawdopodobnie nigdy nie będziemy mieć motywacji, jednak! rozważ
object.Equals()
metodę na każdym obiekcie, która pozwala porównywać obiekty ze sobą, aby sprawdzić, czy są one „takie same”Masz już to, ale powierzono
Array.Sort()
ci zadanie dodania, które możesz chcieć dodaćobject.Compare(object)
źródło