A interface IComparable está desatualizada / "prejudicial"?


11

IComparable só funciona de uma maneira

Digamos que você tenha uma Employeeaula. Em uma exibição, você deseja mostrar todas as Employeesordenadas por nome - em outra, por endereço. Como você vai conseguir isso? Não com IComparable, pelo menos não de maneira idiomática.

IComparable tem a lógica no lugar errado

A interface é usada chamando .Sort(). Em uma exibição que mostra Customerclassificada por nome, não há nenhum código que implique como será classificado.
Por outro lado, a Customerclasse está assumindo como será usada - nesse caso, que será usada em uma lista classificada por nomes.

IComparable é usado implicitamente

Em comparação com as alternativas, é muito difícil ver onde a lógica de comparação está sendo usada - ou se é que existe. Supondo que seu IDE padrão e a partir da Customerclasse, terei que

  1. Pesquise todas as referências a Customer
  2. Encontre as referências usadas em uma lista
  3. Verifique se essas listas já os .Sort()chamaram

O que é provavelmente pior, se você remover uma IComparableimplementação que ainda está sendo usada, você não receberá nenhum erro ou aviso. A única coisa que você terá é o comportamento errado em todos os lugares que eram muito obscuros para você pensar.

Essas questões combinadas, além de requisitos variáveis

O motivo pelo qual eu vim a pensar sobre isso é porque deu errado para mim. Felizmente, uso IComparablemeu aplicativo há 2 anos. Agora, os requisitos foram alterados e a coisa precisa ser classificada de duas maneiras diferentes. Percebeu que não é divertido seguir as etapas descritas na seção anterior.

A questão

Esses problemas me fazem pensar IComparablecomo inferior a IComparerou .OrderBy(), a ponto de não ver nenhum caso de uso válido que não seria melhor atendido pelas alternativas.
É sempre melhor usar IComparerou LINQ, ou existem vantagens / casos de uso que não estou vendo aqui?


2
Seu novo requisito de "classificar duas maneiras diferentes" é um arenque vermelho. Para resolvê-lo, basta passar um comparador diferente para sua função de classificação.
21419 Robert Harvey

@RobertHarvey Então você não usaria IComparablemais, o que está reforçando meu argumento.
R. Schmitz

Não se esqueça de que, se você usar as SortedXXXcoleções, elas exigirão que os elementos armazenados sejam IComparableou sejam IComparerfornecidos. Observe também que é trivial reverter a ordem de classificação natural com um comparador e fazê-la funcionar com todos os IComparableobjetos.
Berin Loritsch 8/0318

2
Não importa que haja duas interfaces diferentes. IComparableé considerado o mecanismo de comparação padrão . ICompareré usado quando você deseja substituir o mecanismo de comparação padrão.
22418 Robert Harvey

Respostas:


14

IComparabletem as restrições que você mencionou, isso está correto. É uma interface que já estava disponível no .NET Framework 1.0, onde essas alternativas funcionais e o Linq não estavam disponíveis. Então, sim, pode-se vê-lo como um elemento de estrutura desatualizado que é mantido principalmente para compatibilidade com versões anteriores.

No entanto, para muitas estruturas simples de dados, uma maneira de classificar é provavelmente suficiente ou natural. Nesses casos, ter um local canônico para implementar o relacionamento do pedido ainda é uma boa maneira de manter o código DRY, em vez de sempre repetir a mesma lógica em todas as chamadas para OrderBytodo o local.

Você está "felizmente usando o IComparable em seu aplicativo há 2 anos", como escreveu, portanto, parece-me que serviu bem por um longo tempo. Quando você agora precisa validar, alterar e testar todas as chamadas Sort, também pode ser um sinal de que você estava fazendo o mesmo tipo de lógica de classificação em muitos lugares, o que não é culpa dele IComparable. Portanto, essa pode ser uma ocasião para centralizar mais essa lógica em um só lugar, tornando seu código mais SECO.


Bom argumento sobre as estruturas de dados simples. No entanto, o último parágrafo não faz 100% de sentido para mim. Se eu não tivesse usado IComparable, todo o código de classificação preexistente teria sido deixado intocado em suas respectivas visualizações, enquanto eu adicionaria apenas um novo código de classificação para a nova exibição.
R. Schmitz

@ R.Schmitz A classificação preexistente funcionaria corretamente sem a IComparableimplementação que você escreveu?
22418 Robert Harvey

3
@ R.Schmitz: Claro, mas agora você está comprometido em sempre fornecer um comparador (a menos que você use OrderBy, é claro). Com IComparable, você obtém uma implementação padrão de graça e, às vezes, nem precisa escrever essa implementação.
22418 Robert Harvey

2
@ R.Schmitz: Seu último comentário resume bem o assunto. Eu iria um pouco mais longe. Suponha que você tenha um tipo numérico como BigInteger. Se não implementasse operadores / interfaces de comparação, como você implementaria um IComparer ? Você precisaria acessar as estruturas de dados internas para fazê-lo com eficiência, ou de todo. Suponha que você tenha um tipo como Cliente; as propriedades públicas que você deseja classificar tarefas têm comparadores. Para mim, essa é a diferença: implemente IComparable<T>se não for razoável esperar que o chamador implemente um comparador.
quer

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.Só porque IComparableera uma solução melhor na época , não significa que é a melhor solução hoje . Seu primeiro comentário aqui implica que "é IComparable ou nada", o que não é verdade, o problema poderia ter sido resolvido de várias maneiras diferentes. Os aplicativos podem crescer em tamanho / escala, e coisas que costumavam parecer adequadas podem não ser capazes de acompanhar as crescentes demandas do aplicativo.
Flater

1

Eu concordo com seus sentimentos sobre IComparable

Basta olhar para as observações em Array.Sort()

  • Cada elemento da matriz deve implementar a IComparableinterface para poder comparar com todos os outros elementos da matriz. (ou exceção é lançada)
  • Se a classificação não for concluída com êxito, os resultados serão indefinidos.

Provavelmente nunca iremos agora a motivação, no entanto! considere object.Equals()um método para cada objeto que permita comparar objetos entre si para ver se eles são "iguais"

Você já o possui, mas recebeu a tarefa de adicionar. Array.Sort()Você pode adicionarobject.Compare(object)

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.