He visto a algunos programadores usar esto:
foreach (var item in items)
{
if (item.Field != null)
continue;
if (item.State != ItemStates.Deleted)
continue;
// code
}
en lugar de donde normalmente usaría:
foreach (var item in items.Where(i => i.Field != null && i.State != ItemStates.Deleted))
{
// code
}
Incluso he visto una combinación de ambos. Realmente me gusta la legibilidad con 'continuar', especialmente con condiciones más complejas. ¿Hay incluso una diferencia en el rendimiento? Con una consulta de base de datos, supongo que la habría. ¿Qué pasa con las listas regulares?
c#
readability
loops
filtering
Pimentón
fuente
fuente
Respuestas:
Consideraría esto como un lugar apropiado para usar la separación de comando / consulta . Por ejemplo:
Esto también le permite dar un buen nombre autodocumentado al resultado de la consulta. También le ayuda a ver oportunidades para refactorizar, porque es mucho más fácil refactorizar el código que solo consulta datos o solo muta datos que el código mixto que intenta hacer ambas cosas.
Al depurar, puede romper antes
foreach
para verificar rápidamente si el contenido de lavalidItems
resolución se ajusta a lo que espera. No tiene que pisar el lambda a menos que lo necesite. Si necesita ingresar a la lambda, le sugiero que la descomponga en una función separada, luego en lugar de eso.¿Hay alguna diferencia en el rendimiento? Si la consulta está respaldada por una base de datos, entonces la versión LINQ tiene el potencial de ejecutarse más rápido, porque la consulta SQL puede ser más eficiente. Si es LINQ to Objects, entonces no verá ninguna diferencia de rendimiento real. Como siempre, perfile su código y corrija los cuellos de botella que realmente se informan, en lugar de tratar de predecir optimizaciones por adelantado.
fuente
IEnumerable
controlaforeach
.Where
lambda y el cuerpo del bucle (si el lambda devuelve verdadero) una vez por elemento.Por supuesto, hay una diferencia en el rendimiento, lo que
.Where()
resulta en una llamada de delegado para cada elemento. Sin embargo, no me preocuparía en absoluto por el rendimiento:Los ciclos de reloj utilizados para invocar a un delegado son insignificantes en comparación con los ciclos de reloj utilizados por el resto del código que itera sobre la colección y verifica las condiciones.
La penalización de rendimiento de invocar a un delegado es del orden de unos pocos ciclos de reloj y, afortunadamente, ya pasamos los días en que teníamos que preocuparnos por los ciclos de reloj individuales.
Si por alguna razón el rendimiento es realmente importante para usted en el nivel del ciclo del reloj, entonces use en
List<Item>
lugar deIList<Item>
, para que el compilador pueda hacer uso de llamadas directas (e inlinables) en lugar de llamadas virtuales, y para que el iterador deList<T>
, que en realidad es astruct
, no tiene que estar en caja. Pero eso es realmente cosas insignificantes.Una consulta de base de datos es una situación diferente, porque existe (al menos en teoría) la posibilidad de enviar el filtro al RDBMS, mejorando así enormemente el rendimiento: solo las filas coincidentes harán el viaje del RDBMS a su programa. Pero para eso creo que tendrías que usar linq, no creo que esta expresión se pueda enviar al RDBMS tal como está.
Que realmente va a ver los beneficios de
if(x) continue;
este momento hay que depurar este código: Single-pasando por encima deif()
s ycontinue
s funciona muy bien; entrar en el delegado de filtrado es un dolor.fuente
if(x) continue;
..Where
solo se invoca una vez. Lo que se invoca en cada iteración es el delegado del filtro (yMoveNext
, yCurrent
en el empadronador, cuando ellos no se han optimizado a cabo).Where
solo se invoca una vez. Arreglado.