Pergunta

Os olhares código como abaixo:

namespace Test
{
    public interface IMyClass
    {
        List<IMyClass> GetList();
    }

    public class MyClass : IMyClass
    {
        public List<IMyClass> GetList()
        {
            return new List<IMyClass>();
        }
    }
}

Quando Análise I executar código eu recebo a seguinte recomendação.

Aviso 3 CA1002: Microsoft.Design: Change 'Lista' em 'IMyClass.GetList ()' para usar coleção, ReadOnlyCollection ou KeyedCollection

Como devo corrigir isso e que é uma boa prática aqui?

Foi útil?

Solução

Para responder o "porquê" parte da questão de saber por que não List<T>, As razões são à prova de futuro e API simplicidade.

Futuro-impermeabilização

List<T> não é projetado para ser facilmente extensível por subclasse-lo; ele é projetado para ser rápido para implementações internas. Você notará os métodos em que não são virtuais e assim não pode ser substituído, e não há ganchos em suas operações Add / Insert / Remove.

Isto significa que se você precisa alterar o comportamento da arrecadação no futuro (por exemplo, para rejeitar objetos nulos que as pessoas tentam adicionar, ou para realizar trabalho adicional quando isso acontece, como atualizar seu estado classe), então você precisa alterar o tipo de coleção que você voltar ao que você pode subclasse, que será uma mudança de interface de ruptura (claro mudar a semântica das coisas não como permitir nulo também pode ser uma mudança de interface, mas coisas como atualizar seu estado classe interna não seria ).

Assim, retornando quer uma classe que pode ser facilmente subclasse como Collection<T> ou uma interface como IList<T>, ICollection<T> ou IEnumerable<T> você pode mudar a sua implementação interna para ser um tipo de coleção diferente para atender às suas necessidades, sem quebrar o código dos consumidores porque ele ainda pode ser retornado como o tipo que eles estão esperando.

API Simplicidade

List<T> contém uma grande quantidade de operações úteis, tais como BinarySearch, Sort e assim por diante. No entanto, se esta é uma coleção que você está expondo, então é provável que você controlar a semântica da lista, e não os consumidores. Assim, enquanto sua classe internamente pode precisar destas operações é muito improvável que os consumidores de sua classe iria querer (ou mesmo deve) chamá-los.

Como tal, através da oferta de uma classe de coleção mais simples ou interface, você reduzir o número de membros que os usuários de seu API ver, e torná-lo mais fácil para eles usarem.

Outras dicas

Eu pessoalmente declará-la para retornar uma interface em vez de uma coleção de concreto. Se você realmente quer o acesso lista, use IList<T> . Caso contrário, considere ICollection<T> e IEnumerable<T> .

É principalmente sobre abstrair suas próprias implementações longe em vez de expor o objeto de lista para ser manipulado diretamente.

Não é boa prática para permitir que outros objetos (ou pessoas) modificar o estado de seus objetos diretamente. Pense getters de propriedade / setters.

Collection -> Para a coleta
normais ReadOnlyCollection -> Para coleções que não deve ser modificado
KeyedCollection -.> Quando você quiser dicionários em vez

Como corrigir isso depende do que você quer que sua classe para fazer e o propósito do método GetList (). Você pode elaborar?

Neste tipo de caso, eu costumo tentar expor a menor quantidade de implemententation que é necessário. Se os consumidores não precisam saber que você está realmente usando uma lista, então você não precisa retornar uma lista. Ao retornar como Microsoft sugere uma coleção que você esconder o fato de que você está usando uma lista dos consumidores de sua classe e isolá-los contra uma mudança interna.

Eu não acho que alguém tenha respondido o "porquê" parte ainda ... então aqui vai. A razão "porque" você "deveria" usar um Collection<T> em vez de um List<T> é porque se você expor um List<T>, então qualquer um que obtém acesso ao seu objeto pode modificar os itens na lista. Considerando Collection<T> é suposto para indicar que você está fazendo a sua própria "Adicionar", "remover", etc métodos.

Você provavelmente não precisa se preocupar com isso, porque provavelmente você está codificação da interface para si mesmo somente (ou talvez alguns colegas). Aqui está outro exemplo que pode fazer sentido.

Se você tiver uma matriz pública, ex:

public int[] MyIntegers { get; }

Você poderia pensar que, porque há apenas um "get" de acesso que ninguém pode mexer com os valores, mas isso não é verdade. Qualquer um pode alterar os valores lá dentro como esta:

someObject.MyIngegers[3] = 12345;

Pessoalmente, eu iria usar apenas List<T> na maioria dos casos. Mas se você está projetando uma biblioteca de classes que você vai dar aos desenvolvedores aleatórios, e você precisa contar com o estado dos objetos ... então você vai querer fazer sua própria coleção e bloqueá-lo para baixo de lá: )

Algo para adicionar que tem sido um longo tempo desde que este foi pedido.

Quando a lista de tipo deriva da List<T> vez de Collection<T>, você não pode implementar os métodos virtuais protegidos que implementa Collection<T>. O que isto significa é que você derivado tipo não pode responder no caso de quaisquer modificações são feitas para a lista. Isso ocorre porque List<T> assume que você está ciente quando você adicionar ou remover itens. Ser capaz de resposta às notificações é uma sobrecarga e que, portanto, List<T> não oferecê-lo.

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 modificado.

Eu não vejo nenhum problema com o retorno algo como

this.InternalData.Filter(crteria).ToList();

Se eu voltasse a desconectado cópia de dados internos, ou resultado desconectada de uma consulta de dados - que eu possa voltar com segurança List<TItem> sem expor qualquer um dos detalhes de implementação, e permitem usar os dados retornados na conveniente caminho.

Mas isso depende de que tipo de consumidor espero - se este é um algo como grade de dados prefiro voltar IEnumerable<TItem> que será a lista copiado de itens de qualquer maneira na maioria dos casos:)

Bem, a classe Collection é realmente apenas uma classe de invólucro em torno de outras coleções para esconder seus detalhes de implementação e outras características. Eu acho que isso tem algo a ver com o esconderijo propriedade padrão em linguagens orientadas a objeto de codificação.

Eu acho que você não deve se preocupar com isso, mas se você realmente quer para agradar a ferramenta de análise de código, basta fazer o seguinte:

//using System.Collections.ObjectModel;

Collection<MyClass> myCollection = new Collection<MyClass>(myList);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top