No meu aplicativo Web ASP.net MVC4, eu uso IEnumerables, tentando seguir o mantra para programar na interface, não na implementação.
Return IEnumerable(Of Student)
vs
Return New List(Of Student)
As pessoas estão me dizendo para usar List e não IEnumerable, porque listas forçam a consulta a ser executada e IEumerable não.
Esta é realmente a melhor prática? Existe alguma alternativa? Eu me sinto estranho usando objetos concretos onde uma interface pode ser usada. Meu sentimento estranho é justificado?
.net
programming-practices
asp.net-mvc
entity-framework
Rowan Freeman
fonte
fonte
Respostas:
Há momentos
ToList()
em que as consultas linq podem ser importantes para garantir que suas consultas sejam executadas no momento e na ordem que você espera. No entanto, esses cenários são raros e nada com que se deve preocupar muito até que eles realmente os encontrem.Para encurtar a história, use
IEnumerable
sempre que precisar de iteração, useIList
quando precisar indexar diretamente e precisar de uma matriz de tamanho dinâmico (se precisar indexar em uma matriz de tamanho fixo, basta usar uma matriz padrão).Como para a coisa tempo de execução, você sempre pode usar uma lista como uma
IEnumerable
variável, tão à vontade para retornar umIEnumerable
fazendo uma.ToList();
, ou passar um parâmetro como umIEnumerable
executando.ToList()
naIEnumerable
execução de força ali mesmo. Apenas tome cuidado para que, sempre que forçar a execução.ToList()
, não se apegue àIEnumerable
variável que você acabou de fazer e a execute novamente, ou então você acabará duplicando as iterações na sua consulta LINQ desnecessariamente.No que diz respeito ao MVC, não há realmente nada de especial a ser observado aqui. Ele seguirá as mesmas regras de tempo de execução que o restante do .NET. Acho que você pode ter alguém confuso causado pela semântica de execução atrasada no passado e culpar o MVC dizendo que isso está relacionado de alguma forma. não. A semântica de execução atrasada confunde todo mundo no começo (e até um bom tempo depois; eles podem ser um pouco complicados). Mais uma vez, porém, não se preocupe até que você realmente se preocupe em garantir que uma consulta LINQ não seja executada duas vezes ou exija que ela seja executada em uma determinada ordem em relação a outro código; nesse ponto, atribua sua variável a ela mesma. ToList () para forçar a execução e você ficará bem.
fonte
List
passear por umList
implica que o conteúdo da lista será modificado. Se você deseja retornar uma coleção, useIReadOnlyCollection
.List
é para uso em métodos e para troca entre métodos que modificam a lista. É isso aí!Existem dois problemas.
Quando o loop "Process Data" é atingido, a consulta pode não ser mais válida. Por exemplo, se a consulta estiver sendo executada em um DataContext que já foi Disposed, seu código emitirá uma exceção. Esse tipo de coisa se torna muito confusa quando você está processando uma consulta em um contexto diferente daquele em que a criou.
Um problema secundário é que sua conexão não será liberada até que o loop "Process Data" seja concluído. Isso é apenas um problema se "Process Data" for complexo. Isso é mencionado em http://msdn.microsoft.com/en-us/library/bb386929.aspx :
Portanto, é por esses motivos que você está sendo incentivado a garantir que a consulta seja realmente executada, por exemplo, chamando
ToList()
. No entanto, como Jimmy sugere , nada o impede de retornar sua lista como um IEnumerable.Como regra geral, eu recomendo evitar a iteração sobre um IEnumerable mais de uma vez. Supondo que os consumidores do seu código sigam essa regra, não considero uma preocupação que alguém possa acessar o banco de dados duas vezes executando a consulta duas vezes.
fonte
Outro benefício de enumerar o
IEnumerable
início é que exceções serão lançadas no local apropriado. Isso ajuda na depuração.Por exemplo, se você tiver uma exceção de deadlock em uma das visualizações do Razor, não será realmente tão claro como se a exceção ocorresse durante um dos métodos de acesso a dados.
fonte
IEnumerable
que possa ser lançado provavelmente está cometendo um erro. OsIEnumerable
métodos diferidos devem ser divididos em dois: um método não diferido verifica os parâmetros e é configurado, lançando, se necessário (por exemplo, devido a um argumento nulo). Em seguida, ele retorna uma chamada para a implementação privada que é adiada. Não acho que meus comentários estejam totalmente em desacordo com sua resposta, mas acho que você deixou de lado um aspecto importante em sua resposta, que é o significado semântico de usarIEnumerable
vs. aList
(mutação) vs.IReadOnlyCollection
(nenhum benefício para adiamento) .