J'écris pas mal de linq dans ma vie quotidienne, mais surtout des déclarations simples. J'ai remarqué qu'en utilisant les clauses where, il y a plusieurs façons de les écrire et chacune a les mêmes résultats, autant que je sache. Par exemple;
from x in Collection
where x.Age == 10
where x.Name == "Fido"
where x.Fat == true
select x;
Cela semble être équivalent au moins en ce qui concerne les résultats:
from x in Collection
where x.Age == 10 &&
x.Name == "Fido" &&
x.Fat == true
select x;
Y a-t-il vraiment une différence autre que la syntaxe? Si oui, quel est le style préféré et pourquoi?
Le second serait plus efficace, car il n’a qu’un prédicat à évaluer par rapport à chaque élément de la collection; comme dans le premier, il applique le premier prédicat à tous les éléments en premier et le résultat (qui est réduit à ce stade) est: utilisé pour le deuxième prédicat et ainsi de suite. Les résultats sont réduits à chaque passage, mais cela implique néanmoins plusieurs passages.
De plus, le chaînage (première méthode) ne fonctionnera que si vous utilisez ANDing vos prédicats. Quelque chose comme ceci x.Age == 10 || x.Fat == true
ne fonctionnera pas avec votre première méthode.
EDIT: LINQ to Objects ne se comporte pas comme prévu. Vous pourriez être intéressé par le article de blog Je viens d'écrire à ce sujet ...
Ils sont différents en termes de ce qui sera appelé - le premier est équivalent à:
Collection.Where(x => x.Age == 10)
.Where(x => x.Name == "Fido")
.Where(x => x.Fat == true)
où ce dernier est équivalent à:
Collection.Where(x => x.Age == 10 &&
x.Name == "Fido" &&
x.Fat == true)
Maintenant, quelle différence cela fait dépend de la mise en oeuvre de Where
appelée. S'il s'agit d'un fournisseur basé sur SQL, je m'attendrais à ce que les deux créent finalement le même code SQL. Si c'est dans LINQ to Objects, le second aura moins de niveaux d'indirection (il n'y aura que deux itérateurs impliqués au lieu de quatre). Que ces niveaux d'indirection soient significatifs en termes de vitesse est une autre affaire.
En règle générale, j'utiliserais plusieurs clauses where
si elles ont le sentiment de représenter des conditions très différentes (par exemple, l'une concerne une partie d'un objet et l'autre est complètement séparée) et une clause where
lorsque diverses conditions sont étroitement liées (par exemple, une valeur particulière est supérieure à un minimum et inférieure à un maximum). En gros, il vaut la peine d’envisager la lisibilité avant toute légère différence de performances.
Le premier sera mis en œuvre:
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
Par opposition à la beaucoup plus simple (et beaucoup plus rapideprobablement plus rapide):
// all in one fell swoop
Collection.Where(x => x.Age == 10 && x.Name == "Fido" && x.Fat == true)
quand je cours
from c in Customers
where c.CustomerID == 1
where c.CustomerID == 2
where c.CustomerID == 3
select c
et
from c in Customers
where c.CustomerID == 1 &&
c.CustomerID == 2 &&
c.CustomerID == 3
select c customer table in linqpad
contre ma table de client, il produit la même requête 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)
donc dans la traduction SQL il n'y a pas de différence et vous avez déjà vu dans d'autres réponses comment elles seront converties en expressions lambda
En regardant sous le capot, les deux déclarations seront transformées en différentes représentations de requête. Selon la QueryProvider
de Collection
, celle-ci peut être optimisée ou non.
Lorsqu'il s'agit d'un appel linq-to-object, plusieurs clauses where mènent à une chaîne d'IEnumerables qui se lisent les unes aux autres. L'utilisation du formulaire à clause unique aidera la performance ici.
Lorsque le fournisseur sous-jacent le traduit en une instruction SQL, il est probable que les deux variantes créeront la même instruction.