Pergunta

O que é o tipo de recipiente preferido quando retornar vários objetos do mesmo tipo de uma função?

É contra a boa prática para retornar uma matriz simples (como MyType []), ou você deve envolvê-la em algum recipiente genérico (como ICollection )?

Obrigado!

Foi útil?

Solução

Eric Lippert tem uma boa href="http://blogs.msdn.com/ericlippert/archive/2008/09/22/arrays-considered-somewhat-harmful.aspx" sobre este assunto. No caso de você não pode ser incomodado para ler o artigo inteiro, a resposta é:. Retornar a interface

Outras dicas

retornar um IEnumerable<T> usando um yield return .

eu gostaria de voltar um IList<T> como que dá ao consumidor da sua função a maior flexibilidade. Dessa forma, se o consumidor da sua função só precisava para enumerar a sequência em que pode fazê-lo, mas se eles querem usar a sequência como uma lista que eles podem fazer isso também.

A minha regra geral é aceitar o tipo menos restritiva como um parâmetro e retornar o tipo mais rico que posso. Este é, naturalmente, um ato de equilíbrio que você não deseja bloquear-se em qualquer interface ou implementação particular (mas sempre, sempre tentar usar uma interface).

Esta é a abordagem menos presunçoso que você, o desenvolvedor API, pode tomar. Não cabe a você decidir como um consumidor de sua função irá usar o que eles te mandam - que é por que você iria retornar um IList<T> neste caso, como para dar-lhes a maior flexibilidade. Também por esta mesma razão que você nunca me atreveria a saber que tipo de parâmetro um consumidor irá enviar-lhe. Se você só precisa iterate uma seqüência enviado a você como um parâmetro em seguida, fazer o parâmetro de um IEnumerable<T> em vez de um List<T>.


EDIT (monóxido): Uma vez que não se parece com a questão vai ser fechada, eu só quero adicionar um link a partir da outra pergunta sobre isso: Por matrizes são prejudiciais

Por que não List<T>?

A partir do pós Eric Lippert mencionado por outros, eu pensei que irá destacar o seguinte:

Se eu precisar de uma seqüência vou usar IEnumerable<T>, se eu precisar de um mapeamento de números contíguos aos dados eu vou usar um List<T>, se eu precisar de um mapeamento através de dados arbitrários Vou usar um Dictionary<K,V>, se eu precisar de um conjunto eu vou usar um HashSet<T>. Eu simplesmente não precisa matrizes para nada, então eu quase nunca usa-os. Eles não resolver um problema I tem melhor do que as outras ferramentas na minha disposição.

Se a coleção que está sendo devolvido é só de leitura, o que significa que você nunca quer os elementos para na coleção para ser mudado, então use IEnumerable<T>. Esta é a representação mais básica de uma sequência única de leitura de imutável (pelo menos do ponto de vista do próprio enumeração) elementos.

Se você quer que ele seja uma coleção auto-suficiente que pode ser mudado, então use ICollection<T> ou IList<T>.

Por exemplo, se você quisesse retornar os resultados da pesquisa por um determinado conjunto de arquivos, em seguida, retornar IEnumerable<FileInfo>.

No entanto, se você queria expor os arquivos em um diretório, no entanto, você iria expor IList/ICollection<FileInfo> como faz sentido que você gostaria de, eventualmente, alterar o conteúdo da coleção.

Um bom conselho que eu oft ouvido citado é o seguinte:

Seja liberal no que você aceitar, preciso em que você fornece.

Em termos de concepção de seu API, eu sugiro que você deve estar retornando uma interface, não um tipo concreto.

Tomar o seu método de exemplo, eu reescrevê-lo da seguinte forma:

public IList<object> Foo() 
{
    List<object> retList = new List<object>();
    // Blah, blah, [snip]
    return retList;
}

A chave é que sua escolha implementação interna - para usar uma lista - não é revelado para o chamador, mas você está retornando uma interface apropriada.

próprias diretrizes da Microsoft no desenvolvimento do enquadramento recomendo contra retornando tipos específicos, favorecendo interfaces. (Desculpe, eu não poderia encontrar um link para isso)

Da mesma forma, seus parâmetros devem ser tão geral quanto possível - em vez de aceitar um array, aceitar um IEnumerable do tipo apropriado. Isto é compatível com matrizes, bem como listas e outros tipos úteis.

Tomar o seu método de exemplo novamente:

public IList<object> Foo(IEnumerable<object> bar) 
{
    List<object> retList = new List<object>();
    // Blah, blah, [snip]
    return retList;
}
return ICollection<type>

A vantagem de tipos de retorno genéricos, é que você pode alterar a implementação subjacente sem alterar o código que o utiliza. A vantagem de devolver o tipo específico, é que você pode usar métodos mais específicos do tipo.

Sempre retornar um tipo de interface que apresenta a maior quantidade de funcionalidade para o chamador. Assim, no seu caso ICollection<YourType> deve ser utilizado.

Algo interessante notar é que os desenvolvedores BCL realmente entendeu errado em algum lugar do framework .NET - veja este Eric Lippert post no blog para essa história.

Por que não IList<MyType>?

Ele suporta indexação direta que é marca registrada de um array sem remover a possibilidade de retornar um List<MyType> algum dia. Se você deseja suprimir esse recurso, você provavelmente vai querer IEnumerable<MyType> retorno.

Depende do que você pretende fazer com a coleção que você está voltando. Se você está apenas repetindo, ou se você quer apenas o usuário para iterate, então eu concordo com @ Daniel, o retorno IEnumerable<T>. Se você realmente quer para permitir operações com base em lista, no entanto, gostaria voltar IList<T>.

Utilize genéricos. É mais fácil para interoperar com outras classes de coleções e do sistema de tipo é mais capaz de ajudá-lo com possíveis erros.

O velho estilo de retornar um array era uma muleta antes genéricos.

O que sempre faz seu código mais legível, de fácil manutenção e fácil para você. Eu teria usado a matriz simples, mais simples == melhor na maioria das vezes. Embora eu realmente tenho que ver o contexto para dar a resposta certa.

Há grandes vantagens para favorecer IEnumerable sobre qualquer outra coisa, pois isso lhe dá a maior flexibilidade de implementação e permite que você use operadores yield return ou Linq para implementação preguiçoso.

Se o chamador quer um List<T> em vez disso, pode simplesmente chamar ToList() sobre o que você voltou, e o desempenho geral será mais ou menos o mesmo que se você tivesse criado e retornado um novo List<T> do seu método.

Array é prejudicial, mas ICollection<T> também é prejudicial.

ICollection<T> não pode garantir o objeto será imutável.

A minha recomendação é para embrulhar o objeto retornando com ReadOnlyCollection<T>

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top