Eu já vi alguns programadores usarem isso:
foreach (var item in items)
{
if (item.Field != null)
continue;
if (item.State != ItemStates.Deleted)
continue;
// code
}
em vez de onde eu normalmente usaria:
foreach (var item in items.Where(i => i.Field != null && i.State != ItemStates.Deleted))
{
// code
}
Eu já vi uma combinação de ambos. Eu realmente gosto da legibilidade com 'continue', especialmente com condições mais complexas. Existe alguma diferença no desempenho? Com uma consulta ao banco de dados, estou assumindo que existiria. E as listas regulares?
c#
readability
loops
filtering
Paprik
fonte
fonte
Respostas:
Eu consideraria isso um local apropriado para usar a separação de comando / consulta . Por exemplo:
Isso também permite que você dê um bom nome de auto-documentação ao resultado da consulta. Também ajuda a ver oportunidades de refatoração, porque é muito mais fácil refatorar o código que apenas consulta dados ou apenas modifica dados do que o código misto que tenta fazer as duas coisas.
Ao depurar, você pode interromper antes
foreach
para verificar rapidamente se o conteúdo davalidItems
resolução está conforme o esperado. Você não precisa entrar no lambda, a menos que precise. Se você precisar entrar no lambda, sugiro fatorá-lo em uma função separada e, em seguida, faça isso.Existe alguma diferença no desempenho? Se a consulta é apoiada por um banco de dados, então a versão LINQ tem o potencial para correr mais rápido, porque a consulta SQL pode ser mais eficiente. Se for LINQ to Objects, você não verá nenhuma diferença real de desempenho. Como sempre, analise seu código e corrija os gargalos que são realmente relatados, em vez de tentar prever otimizações com antecedência.
fonte
IEnumerable
está sendo conduzido apenas peloforeach
loop.Where
lambda e o corpo do loop (se o lambda retornar true) uma vez por elemento.Obviamente, há uma diferença no desempenho,
.Where()
resultando em uma chamada de delegado para cada item. No entanto, eu não me preocuparia com o desempenho:Os ciclos de relógio usados na chamada de um delegado são insignificantes em comparação com os ciclos de relógio usados pelo restante do código que itera sobre a coleção e verifica as condições.
A penalidade de desempenho de chamar um delegado é da ordem de alguns ciclos de relógio e, felizmente, já passamos dos dias em que precisávamos nos preocupar com ciclos de relógio individuais.
Se, por algum motivo, o desempenho for realmente importante para você no nível do ciclo do relógio, use em
List<Item>
vez deIList<Item>
, para que o compilador possa fazer uso de chamadas diretas (e inlináveis) em vez de chamadas virtuais e para que o iterador deList<T>
, na verdade, seja astruct
, não precisa ser encaixotado. Mas isso é realmente insignificante.Uma consulta ao banco de dados é uma situação diferente, porque existe (pelo menos em teoria) a possibilidade de enviar o filtro para o RDBMS, melhorando consideravelmente o desempenho: somente as linhas correspondentes farão a viagem do RDBMS para o seu programa. Mas, para isso, acho que você precisaria usar o linq, não acho que essa expressão possa ser enviada ao RDBMS como está.
Você realmente verá os benefícios do
if(x) continue;
momento em que precisa depurar esse código: Passar por cima deif()
s econtinue
s funciona muito bem; entrar no delegado de filtragem é uma dor.fonte
if(x) continue;
..Where
só é invocado uma vez. O que é invocado em cada iteração é o delegado filtro (eMoveNext
eCurrent
sobre o recenseador, quando eles não são otimizados para fora).Where
só é invocado uma vez. Corrigido.