2011-06-15 15 views
108

Escribo una buena cantidad de linq en mi vida cotidiana, pero en su mayoría declaraciones simples. Me he dado cuenta de que al usar las cláusulas where, hay muchas formas de escribirlas y cada una tiene los mismos resultados que puedo decir. Por ejemplo;Linq adecuado donde las cláusulas

from x in Collection 
    where x.Age == 10 
    where x.Name == "Fido" 
    where x.Fat == true 
    select x; 

parece ser equivalente a este al menos en lo que se refiere a los resultados:

from x in Collection 
    where x.Age == 10 && 
     x.Name == "Fido" && 
     x.Fat == true 
    select x; 

Entonces, ¿hay realmente una diferencia distinta de la sintaxis? Si es así, ¿cuál es el estilo preferido y por qué?

+167

Tiene una propiedad booleana 'Fat'? Eso es claro. –

+81

@Bala R: Oye, si tu perro es gordo, tu perro es gordo. –

Respuesta

61

El segundo sería más eficiente, ya que solo tiene un predicado para evaluar contra cada elemento de la colección donde, como en el primero, aplica primero el primer predicado a todos los elementos y el resultado (que se reduce a este punto) se usa para el segundo predicado y así sucesivamente. Los resultados se reducen en cada pasada, pero aún así implica múltiples pases.

También el encadenamiento (primer método) funcionará solo si está ANDing sus predicados. Algo como esto x.Age == 10 || x.Fat == true no funcionará con su primer método.

+1

La cadena de condiciones de carga es algo posible usando esta extensión: http://www.albahari.com/nutshell/predicatebuilder.aspx – jahu

10

El primero se llevará a cabo:

Collection.Where(x => x.Age == 10) 
      .Where(x => x.Name == "Fido") // applied to the result of the previous 
      .Where(x => x.Fat == true) // applied to the result of the previous 

A diferencia de la mucho más simple (y mucho más rápido presumiblemente más rápido):

// all in one fell swoop 
Collection.Where(x => x.Age == 10 && x.Name == "Fido" && x.Fat == true) 
+4

"Mucho más rápido"? Ni siquiera sabemos qué implementación de LINQ está involucrada todavía, por lo que es difícil asociarle cualquier implicación de rendimiento. –

+0

En el caso general, este último solo requiere 1 ciclo. Un proveedor puede elegir aplanar el primer ejemplo, pero no es obligatorio. – user7116

+2

De hecho ... pero usted está afirmando que este último * es * mucho más rápido. No está nada claro que será * significativamente * más rápido en absoluto; después de todo, la importancia de la diferencia de rendimiento dependerá de cómo se utilice. –

115

EDIT: LINQ a objetos no se comporta como lo esperaba. Usted también puede estar interesado en el blog post que acabo de escribir sobre esto ...


Son diferentes en términos de lo que se llamará - el primero es equivalente a:

Collection.Where(x => x.Age == 10) 
      .Where(x => x.Name == "Fido") 
      .Where(x => x.Fat == true) 

wheras este último es equivalente a:

Collection.Where(x => x.Age == 10 && 
         x.Name == "Fido" && 
         x.Fat == true) 

Ahora lo diferencia de que en realidad hace que depende de la implementación de Where siendo llamado. Si se trata de un proveedor basado en SQL, espero que los dos terminen creando el mismo SQL. Si está en LINQ to Objects, el segundo tendrá menos niveles de indirección (habrá solo dos iteradores involucrados en lugar de cuatro). Si esos niveles de indirección son significativo en términos de velocidad es una cuestión diferente.

Normalmente usaría varias cláusulas where si sienten que están representando condiciones significativamente diferentes (por ejemplo, una tiene que ver con una parte de un objeto, y una está completamente separada) y una cláusula where cuando hay varias condiciones estrechamente relacionadas relacionados (por ejemplo, un valor particular es mayor que un mínimo y menor que un máximo). Básicamente, vale la pena considerar la legibilidad antes de cualquier pequeña diferencia de rendimiento.

+0

@sixlettervariables: Doh, corregido gracias. –

+1

@JonSkeet Quizás estoy equivocado, pero después de una revisión rápida de la implementación de Linq Where, no estoy seguro de eso. Anidado Donde se combinan mediante un método estático 'CombinePredicates'. La recopilación solo se itera una vez por un único iterador con el predicado combinado. Por supuesto, hay un impacto en el rendimiento de combinar func, pero es muy limitado. Estas bien ? – Cybermaxs

+0

@Cybermaxs: ¿No estoy seguro de * qué *, precisamente? Nunca sugerí que la colección se repetirá más de una vez. –

2

Mirando debajo del capó, las dos declaraciones se transformarán en diferentes representaciones de consulta. Dependiendo de QueryProvider de Collection, esto podría optimizarse o no.

Cuando se trata de una llamada de linq a objeto, varias cláusulas where conducirán a una cadena de IEnumerables que se leen entre sí. Usar el formulario de cláusula única ayudará a mejorar el rendimiento aquí.

Cuando el proveedor subyacente lo traduce en una declaración de SQL, existe la posibilidad de que ambas variantes creen la misma declaración.

10

cuando corro

from c in Customers 
where c.CustomerID == 1 
where c.CustomerID == 2 
where c.CustomerID == 3 
select c 

y

from c in Customers 
where c.CustomerID == 1 && 
c.CustomerID == 2 && 
c.CustomerID == 3 
select c customer table in linqpad 

contra mi cliente tabla que muestre la misma consulta SQL

-- Region Parameters 
DECLARE @p0 Int = 1 
DECLARE @p1 Int = 2 
DECLARE @p2 Int = 3 
-- EndRegion 
SELECT [t0].[CustomerID], [t0].[CustomerName] 
FROM [Customers] AS [t0] 
WHERE ([t0].[CustomerID] = @p0) AND ([t0].[CustomerID] = @p1) AND ([t0].[CustomerID] = @p2) 

así en la traducción a SQL no hay diferencia y Ya he visto en otras respuestas cómo se convertirán a expresiones lambda

+0

ok, ¿entonces quieres decir que no tendrá ningún efecto de rendimiento si uso alguno de estos? –

+0

DONDE las cláusulas están encadenadas de hecho. Entonces, no importa cómo lo escribas. No hay diferencia de rendimiento – hastrb

Cuestiones relacionadas