Quando estou escrevendo meu DAL ou outro código que retorna um conjunto de itens, devo sempre fazer minha declaração de retorno:
public IEnumerable<FooBar> GetRecentItems()
ou
public IList<FooBar> GetRecentItems()
Atualmente, tenho tentado usar o IEnumerable em meu código o máximo possível, mas não tenho certeza se essa é a prática recomendada. Parecia correto porque eu estava retornando o tipo de dados mais genérico, embora ainda descritivo do que ele faz, mas talvez isso não seja correto fazer.
c#
ienumerable
KingNestor
fonte
fonte
Respostas:
Realmente depende de por que você está usando essa interface específica.
Por exemplo,
IList<T>
tem vários métodos que não estão presentes emIEnumerable<T>
:IndexOf(T item)
Insert(int index, T item)
RemoveAt(int index)
e propriedades:
T this[int index] { get; set; }
Se você precisar desses métodos de alguma forma, volte por todos os meios
IList<T>
.Além disso, se o método que consome seuIEnumerable<T>
resultado estiver esperando umIList<T>
, ele evitará que o CLR considere quaisquer conversões necessárias, otimizando assim o código compilado.fonte
As diretrizes de design da estrutura recomendam o uso da classe Collection quando você precisa retornar uma coleção que pode ser modificada pelo chamador ou ReadOnlyCollection para coleções somente leitura.
A razão pela qual é preferível a um simples
IList
é queIList
não informa ao chamador se é somente leitura ou não.Se você retornar um em
IEnumerable<T>
vez disso, certas operações podem ser um pouco mais complicadas para o chamador realizar. Além disso, você não dará mais ao chamador a flexibilidade de modificar a coleção, algo que você pode ou não querer.Lembre-se de que o LINQ contém alguns truques na manga e otimizará certas chamadas com base no tipo em que são realizadas. Portanto, por exemplo, se você executar
Count
ae a coleção subjacente for uma Lista, ela NÃO percorrerá todos os elementos.Pessoalmente, para um ORM, provavelmente ficaria com
Collection<T>
meu valor de retorno.fonte
Em geral, você deve exigir o mais genérico e retornar o mais específico que puder. Portanto, se você tiver um método que usa um parâmetro e realmente só precisa do que está disponível em IEnumerable, esse deve ser o seu tipo de parâmetro. Se o seu método puder retornar um IList ou um IEnumerable, prefira retornar IList. Isso garante que seja utilizável por uma ampla gama de consumidores.
Seja frouxo no que você precisa e explícito no que você fornece.
fonte
Depende...
Retornar o tipo menos derivado (
IEnumerable
) deixará a você mais margem de manobra para alterar a implementação subjacente no futuro.Retornar um type mais derivado (
IList
) fornece aos usuários de sua API mais operações no resultado.Eu sempre sugeriria retornar o tipo menos derivado que tem todas as operações de que seus usuários vão precisar ... então, basicamente, você primeiro tem que determinar quais operações no resultado fazem sentido no contexto da API que você está definindo.
fonte
Uma coisa a considerar é que, se você estiver usando uma instrução LINQ de execução adiada para gerar seu
IEnumerable<T>
, chamar.ToList()
antes de retornar do seu método significa que seus itens podem ser iterados duas vezes - uma para criar a Lista e uma vez quando o chamador faz um loop através , filtra ou transforma seu valor de retorno. Quando prático, gosto de evitar converter os resultados do LINQ-to-Objects em uma lista ou dicionário concreto até que seja necessário. Se meu chamador precisa de uma lista, é apenas uma chamada de método fácil - não preciso tomar essa decisão por eles, e isso torna meu código um pouco mais eficiente nos casos em que o chamador está apenas fazendo um foreach.fonte
List<T>
oferece ao código de chamada muitos outros recursos, como modificar o objeto retornado e acessar por índice. Portanto, a questão se resume a: no caso de uso específico do seu aplicativo, você DESEJA oferecer suporte a tais usos (presumivelmente retornando uma coleção recém-construída!), Para a conveniência do chamador - ou você quer velocidade para o caso simples quando todos os O chamador precisa é percorrer a coleção e você pode retornar com segurança uma referência a uma coleção subjacente real, sem temer que isso vá alterá-la erroneamente, etc?Só você pode responder a esta pergunta, e apenas entendendo bem o que seus chamadores vão querer fazer com o valor de retorno e quão importante é o desempenho aqui (quão grandes são as coleções que você estaria copiando, qual a probabilidade de isso ser um gargalo, etc).
fonte
Se a coleção se destina a ser somente leitura ou a modificação da coleção é controlada pelo
Parent
, retornar umIList
justCount
for não é uma boa ideia.No Linq, há um
Count()
método de extensão noIEnumerable<T>
qual dentro do CLR atalho para.Count
se o tipo subjacente for deIList
, portanto, a diferença de desempenho é insignificante.Geralmente eu sinto (opinião) que é uma prática melhor retornar IEnumerable onde possível, se você precisar fazer adições, então adicione esses métodos à classe pai, caso contrário, o consumidor está gerenciando a coleção dentro de Model que viola os princípios, por exemplo,
manufacturer.Models.Add(model)
viola a lei de demeter. É claro que essas são apenas diretrizes e não regras rígidas e rápidas, mas até que você tenha total compreensão da aplicabilidade, seguir cegamente é melhor do que não seguir de forma alguma.(Nota: Se estiver usando nNHibernate, você pode precisar mapear para IList privado usando acessores diferentes.)
fonte
Não é tão simples quando você está falando sobre valores de retorno em vez de parâmetros de entrada. Quando é um parâmetro de entrada, você sabe exatamente o que precisa fazer. Portanto, se você precisar iterar na coleção, pegue um IEnumberable, enquanto se precisar adicionar ou remover, você pega um IList.
No caso de um valor de retorno, é mais difícil. O que seu chamador espera? Se você retornar um IEnumerable, ele não saberá a priori que pode fazer um IList disso. Mas, se você retornar um IList, ele saberá que pode iterar sobre ele. Portanto, você deve levar em consideração o que seu chamador fará com os dados. A funcionalidade que seu chamador precisa / espera é o que deve reger ao tomar a decisão sobre o que retornar.
fonte
como todos disseram, depende, se você não quiser Adicionar / Remover funcionalidade na camada de chamada, então votarei no IEnumerable, pois ele fornece apenas iteração e funcionalidade básica que em prespectiva de design eu gosto. Retornando IList meus votos são sempre novamente, mas é principalmente o que você gosta e o que não é. em termos de desempenho, acho que são mais do mesmo.
fonte
Se você não contar em seu código externo é sempre melhor retornar IEnumerable, porque posteriormente você pode alterar sua implementação (sem impacto no código externo), por exemplo, para render a lógica do iterador e conservar recursos de memória (recurso de linguagem muito bom por sinal )
No entanto, se você precisar da contagem de itens, não se esqueça de que há outra camada entre IEnumerable e IList - ICollection .
fonte
Posso estar um pouco errado aqui, visto que ninguém mais sugeriu até agora, mas por que você não retorna um
(I)Collection<T>
?Pelo que me lembro,
Collection<T>
era o tipo de retorno preferencialList<T>
porque abstrai a implementação. Todos eles implementamIEnumerable
, mas isso me parece um nível um pouco baixo demais para o trabalho.fonte
Acho que você pode usar qualquer um, mas cada um tem uma utilidade. Basicamente
List
é,IEnumerable
mas você tem a funcionalidade de contagem, Adicionar elemento, remover elementoIEnumerable
não é eficiente para contar elementos ou obter um elemento específico na coleção.List
é uma coleção ideal para encontrar elementos específicos, fácil de adicionar ou remover.Geralmente tento usar sempre
List
que possível, pois isso me dá mais flexibilidade.Use em
List<FooBar> getRecentItems()
vez deIList<FooBar> GetRecentItems()
fonte
Acho que a regra geral é usar a classe mais específica para retornar, para evitar fazer trabalhos desnecessários e dar mais opções ao chamador.
Dito isso, acho que é mais importante considerar o código à sua frente, que você está escrevendo, do que o código que o próximo cara escreverá (dentro do razoável). Isso ocorre porque você pode fazer suposições sobre o código que já existe.
Lembre-se de que mover UP para uma coleção de IEnumerable em uma interface funcionará, mover para baixo para IEnumerable de uma coleção quebrará o código existente.
Se todas essas opiniões parecem conflitantes, é porque a decisão é subjetiva.
fonte
TL; DR; - resumo
List
) para os valores de retorno e o tipo mais genérico para os parâmetros de entrada, mesmo no caso de coleções.IReadOnlyList
ouIReadOnlyCollection
como o tipo de valor de retorno.Mais
fonte