Para responder à parte "por que" da pergunta e por que não List<T>
, os motivos são a prova do futuro e a simplicidade da API.
À prova de futuro
List<T>
não foi projetado para ser facilmente extensível subclassificando-o; Ele foi projetado para ser rápido para implementações internas. Você notará que os métodos nele não são virtuais e, portanto, não podem ser substituídos, e não há ganchos em suas operações Add
/ Insert
/ Remove
.
Isso significa que, se você precisar alterar o comportamento da coleção no futuro (por exemplo, para rejeitar objetos nulos que as pessoas tentam adicionar ou executar trabalhos adicionais quando isso acontecer, como atualizar o estado da classe), será necessário alterar o tipo da coleção, você retorna para uma subclasse que pode ser quebrada, o que será uma mudança na interface (é claro que mudar a semântica de coisas como não permitir nulo também pode ser uma alteração na interface, mas coisas como atualizar o estado da classe interna não seriam).
Portanto, retornando uma classe que possa ser facilmente subclassificada Collection<T>
ou uma interface como IList<T>
, ICollection<T>
ou IEnumerable<T>
você pode alterar sua implementação interna para ser um tipo de coleção diferente para atender às suas necessidades, sem quebrar o código dos consumidores, pois ainda pode ser retornado como o tipo que eles estão esperando.
Simplicidade da API
List<T>
contém uma série de operações úteis, tais como BinarySearch
, Sort
e assim por diante. No entanto, se esta é uma coleção que você está expondo, é provável que você controle a semântica da lista, e não os consumidores. Portanto, embora sua classe internamente precise dessas operações, é muito improvável que os consumidores da sua classe desejem (ou até devam) chamá-las.
Dessa forma, ao oferecer uma classe ou interface de coleção mais simples, você reduz o número de membros que os usuários da sua API veem e facilita o uso deles.
Eu pessoalmente declararia que ele retornaria uma interface em vez de uma coleção concreta. Se você realmente deseja acesso à lista, use
IList<T>
. Caso contrário, considereICollection<T>
eIEnumerable<T>
.fonte
We recommend using Collection<T>, ReadOnlyCollection<T>, or KeyedCollection<TKey,TItem> for outputs and properties and interfaces IEnumerable<T>, ICollection<T>, IList<T> for inputs.
CA1002 , parece concordar com os comentários de Krzysztof. Não consigo imaginar por que uma coleção concreta seria recomendada em vez de uma interface e por que a distinção entre entradas / saídas.ReadOnlyCollection<T>
, não faria sentido para uma entrada. Da mesma forma,IList<T>
como uma entrada diz: "Preciso de Sort () ou de algum outro membro que um IList tenha", o que não faz sentido para uma saída. Mas o que eu quis dizer foi: por queICollection<T>
seria recomendado como entrada eCollection<T>
como saída. Por que não usarICollection<T>
como saída também como você sugeriu?Collection<T>
eReadOnlyCollection<T>
ambos derivam deICollection<T>
(isto é, não háIReadOnlyCollection<T>
). Se você retornar a interface, não é óbvio qual é e se pode ser modificado. De qualquer forma, obrigado pela sua contribuição. Esta foi uma boa verificação de sanidade para mim.Acho que ninguém respondeu à parte "por que" ainda ... então aqui vai. A razão pela qual "você" deve "usar um em
Collection<T>
vez de aList<T>
é porque, se você expõe aList<T>
, qualquer pessoa que obtém acesso ao seu objeto pode modificar os itens da lista. Considerando queCollection<T>
deve indicar que você está criando seus próprios métodos "Adicionar", "Remover", etc.Você provavelmente não precisa se preocupar com isso, porque provavelmente está codificando a interface apenas para si (ou talvez para alguns colegas). Aqui está outro exemplo que pode fazer sentido.
Se você tiver uma matriz pública, ex:
Você pensaria isso porque existe apenas um acessador "get" que ninguém pode mexer com os valores, mas isso não é verdade. Qualquer um pode alterar os valores lá dentro, assim:
Pessoalmente, eu usaria apenas
List<T>
na maioria dos casos. Mas se você estiver projetando uma biblioteca de classes que irá distribuir para desenvolvedores aleatórios e precisar confiar no estado dos objetos ... então você desejará criar sua própria coleção e bloqueá-la a partir daí: )fonte
É principalmente abstrair suas próprias implementações, em vez de expor o objeto List a ser manipulado diretamente.
Não é uma boa prática permitir que outros objetos (ou pessoas) modifiquem diretamente o estado dos seus objetos. Pense em getters / setters de propriedades.
Coleção -> Para coleção normal
ReadOnlyCollection -> Para coleções que não devem ser modificadas
KeyedCollection -> Quando você deseja dicionários.
Como corrigi-lo depende do que você deseja que sua classe faça e da finalidade do método GetList (). Você pode elaborar?
fonte
ReadOnlyCollection
os outros dois não obedece.GetList()
poder ajudá-lo mais corretamente.Collection<T>
ajuda a abstrair a implementação interna e impede a manipulação direta da lista interna. Quão?Collection<T>
é apenas um wrapper, operando na mesma instância passada. É uma coleção dinâmica destinada à herança, nada mais (a resposta de Greg é mais relevante aqui).Nesse tipo de caso, geralmente tento expor a menor quantidade de implementação necessária. Se os consumidores não precisarem saber que você está realmente usando uma lista, não será necessário retornar uma lista. Ao retornar como a Microsoft sugere uma coleção, você oculta o fato de estar usando uma lista dos consumidores de sua classe e os isola de uma alteração interna.
fonte
Algo a acrescentar, embora tenha sido um longo tempo desde que isso foi solicitado.
Quando seu tipo de lista deriva em
List<T>
vez deCollection<T>
, você não pode implementar os métodos virtuais protegidos queCollection<T>
implementam. O que isto significa é que o seu tipo derivado não pode responder caso sejam feitas modificações na lista. Isso ocorre porqueList<T>
assume que você está ciente quando adiciona ou remove itens. Ser capaz de responder a notificações é uma sobrecarga e, portantoList<T>
, não a oferece.Nos casos em que o código externo tem acesso à sua coleção, você pode não estar no controle de quando um item está sendo adicionado ou removido. Portanto,
Collection<T>
fornece uma maneira de saber quando sua lista foi modificada.fonte
Não vejo nenhum problema em retornar algo como
Se eu retornei uma cópia desconectada dos dados internos ou o resultado desanexado de uma consulta de dados - posso retornar com segurança
List<TItem>
sem expor nenhum detalhe da implementação e permitir o uso dos dados retornados da maneira conveniente.Mas isso depende do tipo de consumidor que eu espero - se é algo como uma grade de dados, prefiro retornar,
IEnumerable<TItem>
que na maioria dos casos será a lista de itens copiada :)fonte
Bem, a classe Collection é realmente apenas uma classe de wrapper em torno de outras coleções para ocultar seus detalhes de implementação e outros recursos. Eu acho que isso tem algo a ver com o padrão de codificação da propriedade oculta nas linguagens orientadas a objetos.
Acho que você não deve se preocupar com isso, mas se realmente deseja agradar a ferramenta de análise de código, faça o seguinte:
fonte
Collection<T>
não protege a si mesmo nem a coleção subjacente, tanto quanto eu entendo.Collection<T>
protegerá imediatamente sua coleção subjacente.