2009-10-30 9 views
12

Soy nuevo en LINQ y descubrió ayer que se pueden tener varias cláusulas WHERE como:Al usar LINQ, ¿cuál es la diferencia entre && y las cláusulas where?

var items = from object in objectList 
where object.value1 < 100 
where object.value2 > 10 
select object; 

O puede escribir:

var items = from object in objectList 
where object.value1 < 100 
    && object.value2 > 10 
select object; 

¿Cuál es la diferencia entre los dos?

Respuesta

17

El primero de ellos se traducirán a:

objectList.Where(o => o.value1 < 100).Where(o=> o.value2 > 10) 

mientras que la segunda se traduce en:

objectList.Where(o => o.value1 < 100 && o.value2 > 10) 

Así, en el primero de ellos, tendrá una primera secuencia filtrada que se filtra nuevamente (la primera secuencia contiene todos los objetos con valor < 100, la segunda contiene todos los objetos con valor> 10 de la primera secuencia), mientras que la segunda hará las mismas comparaciones en la misma expresión labda. Esto es válido para los objetos de Linq, para otros proveedores depende de cómo se traduzca la expresión.

+1

En realidad eso es bastante inexacto. Si inspecciona las fuentes de 'Linq', verá que' Where' tiene un método que traduce '.Where (x) .Where (y)' en '.Where (x && y)'. [fuente] (http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,f7e72dc9c9621f30) –

+0

Buen punto, no puedo decir si revisé esto en 2009 o si fue cierto todo el tiempo. – Philippe

1

En el nivel más básico, obtienes dos operaciones Where en lugar de una. El uso de Reflector es la mejor manera de examinar lo que sale al otro lado de una expresión de consulta.

Si se optimizan hasta lo mismo depende del proveedor de LINQ real - necesita tomar todo el árbol y convertirlo a otra sintaxis. Para LINQ To Objects, no es así.

C# in Depth es bueno para darle una comprensión de este tema.

6

El primero de ellos se traduce en:

objectList.Where(o => o.value1 < 100) 
      .Where(o => o.value2 > 10); 

mientras que el segundo se obtiene:

objectList.Where(o => o.value1 < 100 && o.value2 > 10);  

Es functionnaly la misma, y ​​mientras que el segundo sería prescindir de una llamada al método, la diferencia de rendimiento es despreciable. Usa lo que es más legible para ti.

Es decir, si está utilizando linq para objetos. Si está utilizando un proveedor, depende de cómo se implemente (si el predicado no se tiene en cuenta en la consulta resultante, el resultado puede ser subóptimo).

+0

Realmente lo escribí directamente. Tienes razón, el selector de identidad no tiene sentido. –

0

¿Qué tal esto para una respuesta: con & & no se puede garantizar que se evalúen ambas expresiones con (si la primera condición es falsa, entonces el segundo podría no evaluarse). Con las dos cláusulas where, entonces puedes. ¡No tengo idea de si es verdad, pero me parece bien!

+2

No creo que sea cierto. Si es Linq to Objects, la primera Where-call devolverá una enumeración que solo contiene los elementos donde la condición 1 es verdadera. Por lo tanto, la condición 2 solo se solicitará para estos artículos. – Niki

+0

Correcto, ¿pero no es todo lo contrario? Digamos que usa un simple '&', luego ambos serán evaluados en el segundo caso. De todos modos, mejor evitar el uso de efectos secundarios en estos :) – Philippe

0

En igualdad de condiciones, elegiría la versión condition1 && condition2, por el bien de la legibilidad del código.

3

Acabo de perfilarlo. Sin diferencia en el código SQL

+0

Suponiendo que el OP estaba hablando de LINQ a SQL. =) –

6

La respuesta correcta es un poco inexacta.

Como dijo @Philippe, el primero que se traducirán a:

objectList.Where(o => o.value1 < 100).Where(o=> o.value2 > 10) 

mientras que la segunda se traduce en:

objectList.Where(o => o.value1 < 100 && o.value2 > 10) 

PeroLinq tiene una poca optimización para llamadas encadenadas Where.

Si inspecciona Linq's código fuente se verá lo siguiente:

class WhereEnumerableIterator<TSource> : Iterator<TSource> 
{ 
    public override IEnumerable<TSource> Where(Func<TSource, bool> predicate) 
    { 
     return new WhereEnumerableIterator<TSource>(source, 
      CombinePredicates(this.predicate, predicate)); 
    } 
} 

Lo CombinePredicates no se está combinando los dos predicados con && entre ellos:

static Func<TSource, bool> CombinePredicates<TSource>(Func<TSource, bool> predicate1, 
    Func<TSource, bool> predicate2) 
{ 
    return x => predicate1(x) && predicate2(x); 
} 

Así objectList.Where(X).Where(Y) es equivalente a objectList.Where(X && Y) excepto por el tiempo de creación de la consulta (que de todos modos es extremadamente corto) y la invocación de dos predicados.

El fondo es que no lo hace filtro o iterar la colección dos veces - pero una vez compuesto.

Cuestiones relacionadas