L'interfaccia IComparable è obsoleta / "dannosa"?


11

IComparable funziona solo in un modo

Diciamo che hai una Employeelezione. In una vista, vuoi mostrare tutto Employeesordinato per nome - in un'altra, per indirizzo. Come lo farai? Non con IComparable, almeno non in alcun modo idiomatico.

IComparable ha la logica nel posto sbagliato

L'interfaccia viene utilizzata chiamando .Sort(). In una vista mostrata Customerordinata per nome, non esiste alcun codice che implichi il modo in cui verrà ordinata.
D'altra parte, la Customerclasse presuppone come verrà utilizzata, in questo caso verrà utilizzata in un elenco ordinato per nome.

IComparable è usato implicitamente

In confronto con le alternative, è molto difficile vedere dove viene utilizzata la logica di confronto - o se non del tutto. Supponendo il tuo IDE standard e partendo dalla Customerclasse, dovrò

  1. Cerca tutti i riferimenti a Customer
  2. Trova i riferimenti utilizzati in un elenco
  3. Controlla se quegli elenchi .Sort()li hanno mai chiamati

Quel che è probabilmente peggio, se si rimuove IComparableun'implementazione ancora in uso, non si ottiene alcun errore o avviso. L'unica cosa che otterrai è un comportamento sbagliato in tutti i luoghi che erano troppo oscuri per farti pensare.

Questi problemi combinati, oltre a cambiare i requisiti

La vera ragione per cui sono venuto a pensarci è perché è andato storto per me. Uso felicemente la IComparablemia candidatura da 2 anni. Ora, i requisiti sono cambiati e la cosa deve essere ordinata in 2 modi diversi. Ha notato che non è divertente passare attraverso i passaggi descritti nella sezione precedente.

La domanda

Questi problemi mi fanno pensare IComparableche sia inferiore IComparero .OrderBy(), al punto da non vedere alcun caso d'uso valido che non sarebbe servito meglio dalle alternative.
È sempre meglio usare IComparero LINQ o ci sono vantaggi / casi d'uso che non vedo qui?


2
Il tuo nuovo requisito "ordina due modi diversi" è un'aringa rossa. Per risolverlo, tutto ciò che devi fare è passare un comparatore diverso alla tua funzione di ordinamento.
Robert Harvey,

@RobertHarvey Allora non useresti IComparablepiù, il che sta rafforzando il mio punto.
R. Schmitz,

Non dimenticare che se si utilizzano le SortedXXXraccolte, richiedono che gli elementi archiviati siano IComparableo siano IComparerforniti. Si noti inoltre che è banale invertire l'ordine di ordinamento naturale con un comparatore e farlo funzionare con tutti gli IComparableoggetti.
Berin Loritsch,

2
Non importa che ci siano due diverse interfacce. IComparableè considerato il meccanismo di confronto predefinito . IComparerviene utilizzato quando si desidera sovrascrivere il meccanismo di confronto predefinito.
Robert Harvey,

Risposte:


14

IComparableha le restrizioni che hai citato, è corretto. È un'interfaccia che era già disponibile in .NET Framework 1.0, dove quelle alternative funzionali e Linq non erano disponibili. Quindi sì, si potrebbe vederlo come un elemento framework obsoleto, che viene mantenuto principalmente per compatibilità con le versioni precedenti.

Tuttavia, per molte semplici strutture di dati, un modo di ordinare è probabilmente sufficiente o naturale. In questi casi, avere un posto canonico per implementare la relazione d'ordine è ancora un buon modo per mantenere il codice DRY, invece di ripetere sempre la stessa logica in ogni chiamata a OrderBytutto il luogo.

"Usi felicemente IComparable nella tua applicazione da 2 anni", come hai scritto, quindi mi sembra che ti sia servito bene per molto tempo. Quando ora devi convalidare, modificare e testare tutte le chiamate Sort, potrebbe anche essere un segno che stavi facendo lo stesso tipo di logica di ordinamento in molti punti, di cui non è colpa IComparable. Quindi questa potrebbe essere un'occasione per centralizzare più di questa logica in un unico posto, rendendo il tuo codice più ASCIUTTO.


Un buon punto sulle semplici strutture dati. Tuttavia, l'ultimo paragrafo non ha senso al 100% per me. Se non avessi usato IComparable, tutto il codice di ordinamento preesistente sarebbe rimasto intatto nelle rispettive viste, mentre aggiungerei solo un nuovo codice di ordinamento per la nuova vista.
R. Schmitz,

@ R.Schmitz L'ordinamento preesistente avrebbe funzionato correttamente senza l' IComparableimplementazione che hai scritto?
Robert Harvey,

3
@ R.Schmitz: Certo, ma ora ti impegni a fornire sempre un comparatore (a meno che tu non usi OrderBy, ovviamente). Con IComparable, ottieni un'implementazione predefinita gratuitamente e a volte non devi nemmeno scriverla.
Robert Harvey,

2
@ R.Schmitz: il tuo ultimo commento qui riassume bene il punto. Vorrei andare un po 'più lontano però. Supponiamo di avere un tipo numerico come BigInteger. Se non implementasse operatori / interfacce di confronto come implementeresti tu stesso un IComparer ? Avresti bisogno dell'accesso alle strutture di dati interne per farlo in modo efficiente, o per niente. Supponiamo di avere un tipo come Cliente; le proprietà pubbliche si desidera ordinare il do avere comparatori. Per me questa è la differenza: implementare IComparable<T>se sarebbe irragionevole aspettarsi che il chiamante implementi un comparatore.
Eric Lippert,

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.Solo perché IComparableera una migliore soluzione , al momento , non significa che è il migliore soluzione di oggi . Il tuo primo commento qui implica che "è IComparable o niente", il che non è vero, il problema avrebbe potuto essere risolto in molti modi diversi. Le applicazioni possono crescere in dimensioni / dimensioni e le cose che sembravano adatte potrebbero non essere in grado di tenere il passo con le crescenti richieste dell'applicazione.
Flater,

1

Sono d'accordo con i tuoi sentimenti in merito IComparable

Guarda le osservazioni su Array.Sort()

  • Ogni elemento dell'array deve implementare l' IComparableinterfaccia per poter essere confrontato con ogni altro elemento dell'array. (o viene generata un'eccezione)
  • Se l'ordinamento non viene completato correttamente, i risultati non sono definiti.

Probabilmente non avremo mai ora la motivazione, tuttavia! considera object.Equals()un metodo su ogni oggetto che ti consente di confrontare gli oggetti tra loro per vedere se sono "uguali"

Lo hai già lì, ma ti è stato assegnato il compito di aggiungere Array.Sort()che potresti voler aggiungereobject.Compare(object)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.