C# 3.0 : Syntaxe d'une requête LINQ
Les débutants à LINQ vont être nombreux dans les jours qui suivent. Je vous propose donc un récapitulatif de la syntaxe des requêtes LINQ en C#. Je me suis inspiré de cet article, très complet, mais peu didactique (il s'agit en fait d'un extrait des spécifications de C# 3.0).
Une requête LINQ est composée de plusieurs clauses les unes à la suite des autres. La compilation d'une requête LINQ utilise un mécanisme de mapping syntaxique : chaque clause (sauf le from de départ et into) a un nom de méthode correspondant (par exemple, pour la clause where, la méthode correspondante est Where). Lors de la compilation, le compilateur va transformer chaque clause en un appel à la méthode correspondante. Les spécifications du langage ne précisent pas ce que doit faire cette méthode, mais juste son nom (LINQ to Objects et LINQ to SQL utilisent par exemple des implémentations différentes).
Cela peut être une méthode d'instance, ou une méthode d'extension. Si vous utilisez une clause et qu'aucune méthode du nom correspondant n'existe, ou si les paramètres ne correspondent pas, vous obtiendrez une erreur de compilation.
Construction d'une requête LINQ
Voici la liste des clauses utilisables depuis C# 3.0, je les ai séparées en 4 catégories pour mieux décrire la structure d'une requête.
- La clause de début de requête
from [type] identifier in sourceExpr
- Les clauses intermédiaires
from [type] identifier in sourceExpr
let identifier = selectorExpr
where predicateExpression
join [type] identifier in sourceExpr on keyExpr equals keyExpr
join [type] identifier in sourceExpr on keyExpr equals keyExpr into identifier
orderby orderings
- Les clauses de fin de requête
select selectorExpr
group selectorExpr by keyExpr
into identifier
Une requête LINQ simple (sans clause into) est construite de la façon suivante :
- Une clause de début (from ... in ...)
- Zéro ou plusieurs clauses intermédiaires (dans l'ordre que vous voulez)
- Une clause de fin (select ou group)
La clause into
Il est aussi possible d'enchainer plusieurs "sous-requêtes" à l'aide de clauses into.
La clause into n'est pas traduite par un appel de méthode. Elle permet d'améliorer la lisibilité de requêtes imbriquées, en réintroduisant le résultat d'une sous-requête dans la suivante.
Les sous-requêtes constituant une même requête sont simplement écrites les unes à la suite des autres, séparées entre elles par des clauses into.
La première sous-requête suit exactement la constitution d'une requête simple (voir ci-dessus). Les sous-requêtes suivantes, sont constituées comme une requête simple, sauf qu'elles n'ont pas de requête from de début, en effet, la variable muette est introduite par la clause into qui précède la sous requête.
La requête suivante avec into :
from sub-query1
into identifier
sub-query2
est traduite en ceci par le compilateur (sans into) :
from identifier in (from sub-query1)
sub-query2
Attention : Le mot clé into a une signification différente s'il est utilisé dans une clause join / into ou dans une clause into.
Schéma récapitulatif
Voici un schéma pour synthétiser tout cela :

Les flèches vertes représentent le début et la fin de la requête. Pour le groupe des clauses intermédiaires, vous pouvez choisir zéro, une ou plusieurs clauses parmi celles possibles (0 or more), ordonnées dans l'ordre que vous souhaitez. Pour les 3 autres groupes, vous devez choisir exactement une clause dans le groupe (1).
Les variables internes à la requête
Chaque requête LINQ commence forcément par une clause from, celle-ci introduit une range variable (variable muette). Il est aussi possible d'utiliser des clauses from additionnelles en tant que clauses intermédiaires pour ajouter d'autres range variables. Les clauses intermédiaires let, join et join/into introduisent également de nouvelles range variables pour les clauses qui les suivent.
La clause into introduit aussi une nouvelle range variable, mais efface toutes les range variables précédemment déclarées (seules les range variables déclarées dans la même sous-requête sont accessibles).
Equivalences entre clause et nom de méthode
| Clause LINQ |
Nom de méthode correspondant |
| Clauses intermédiaires |
| from |
SelectMany |
| let |
Select |
| where |
Where |
| join |
Join |
| join into |
GroupJoin |
| orderby |
OrderBy, OrderByDescending, ThenBy, ThenByDescending |
| Clauses de fin |
| select |
Select (ou rien) |
| group |
GroupBy |
La méthode Cast peut aussi être utilisée si vous spécifiez un type dans une clause from, join ou join into.
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :