Les versions récentes du langage C sharp permettent d'utiliser une expression de requête sur un ensemble de données itérables en utilisant une syntaxe similaire à celle des requêtes de base de données.
Cette intégration de la syntaxe de requête dans le langage s'appelle en anglais "Language Integrated Query" (LINQ).
Syntaxe.
Le mot clé codice_1 sert à introduire une expression de requête.
Il est suivi par le nom de la variable qui référencera les valeurs itérées, du mot-clé codice_2, de l'ensemble de données itéré et d'un nombre d'instructions de requête (sélection, groupement, tri, etc.).
L'ensemble de données doit implémenter l'interface codice_3 ou une interface dérivée comme codice_4 ; le type T est alors utilisé par le compilateur pour définir le type générique pour la variable qui référencera les valeurs itérées.
Si l'ensemble de données implémente l'interface codice_5 (sans type d'élément spécifié, comme la classe codice_6), le type d'élément doit être spécifié.
En clair, cela transforme un ensemble IEnumerable en un autre ensemble IEnumerable itérant des éléments du même type (ou codice_7 pour une clause de groupement), mais filtrant et éventuellement réordonnant les éléments de l'ensemble initial.
Exemple : N'afficher que les entiers pairs d'un tableau
// L'ensemble des données
int[] les_nombres = new int[5] { 12, 11, 24, 28, 17 };
// Requête : nombres_pairs est de type IEnumerable<int>
var nombres_pairs =
 from nombre in les_nombres
 where (nombre % 2) == 0
 select nombre;
// Exécution de la requête : itération sur les résultats
foreach (int nombre_pair in nombres_pairs)
 Console.WriteLine("Nombre pair : {0}", nombre_pair);
// N'affiche que les nombres pairs du tableau les_nombres :
// Nombre pair 12
// Nombre pair 24
// Nombre pair 28
La requête n'est pas exécutée immédiatement, mais lors de l'itération avec la boucle codice_8.
Elle est également déclenchée par l'appel à une méthode de l'interface codice_5 nécessitant le parcours des éléments :
// les_nombres_pairs est de type int[]
var les_nombres_pairs =
 (from nombre in les_nombres
 where (nombre % 2) == 0
 select nombre).ToArray();
La requête semble réaliser l'équivalent d'une boucle combinée à une condition.
Cependant elle permet également de trier les résultats, de les regrouper, et il est possible de passer la requête à une fonction ayant besoin d'un ensemble de valeurs itérables.
Ces cas d'utilisations seraient beaucoup plus complexes à réaliser sans la syntaxe des expressions de requête.
Quand l'ensemble de données implémente l'interface codice_5 sans type d'élément spécifié, comme la classe codice_6 par exemple, le type d'élément doit être spécifié pour la variable comme dans l'exemple suivant :
ArrayList listeDeNom = new ArrayList();
listeDeNom.add("exemple");
listeDeNom.add("de liste");
listeDeNom.add("contenant");
listeDeNom.add("des valeurs");
var nom_longs =
 from string nom in listeDeNom
 where nom.length > 8
 select nom;
Clauses de requête.
Différentes clauses suivent la définition de la source de données, traitées dans l'ordre, chacune introduite par un mot-clé :
Filtre.
Le filtrage des éléments est introduit par le mot-clé codice_18 suivi d'une expression booléenne définissant la condition pour que l'élément apparaisse dans l'itération des résultats de la requête.
var petits_nombres_pairs =
 from nombre in les_nombres
 where ((nombre % 2) == 0) && (nombre < 20)
 select nombre;
Plusieurs clauses codice_18 peuvent être utilisées à la suite permettant de valider toutes les conditions, comme l'opérateur "et" utilisé dans l'exemple précédent.
Exemple équivalent au précédent :
var petits_nombres_pairs =
 from nombre in les_nombres
 where (nombre % 2) == 0
 where nombre < 20
 select nombre;
Sélection.
La clause codice_23 définit la valeur retournée à chaque itération des résultats de la requête, et détermine aussi le type du paramètre générique des résultats itérables.
// Requête : nombres_pairs_romains est de type IEnumerable<string>
var nombre_pairs_romains =
 from nombre in les_nombres
 where (nombre % 2) == 0
 select NombreEnChiffresRomains(nombre);
// Exécution de la requête : itération sur les résultats
foreach (string nombre_pair_romain in nombres_pairs_romains)
 Console.WriteLine("Nombre pair : {0}", nombre_pair_romain);
// Si l'hypothétique fonction NombreEnChiffresRomains
// retourne bien la représentation en chiffres romains :
// Nombre pair XII
// Nombre pair XXIV
// Nombre pair XXVIII
Tri.
Les résultats peuvent être triant en utilisant la clause codice_22.
Ce mot-clé est suivi d'une liste d'expressions définissant chacune la valeur de critère pour définir l'ordre des résultats.
Chacun de ces critères est optionnellement suivi du mot-clé codice_28 pour un tri dans l'ordre croissant, ou du mot-clé codice_29 pour un tri dans l'ordre décroissant.
S'il n'est pas spécifié, le tri est en ordre croissant.
Exemple simple :
// L'ensemble des données
string[] les_mois = new int[12]
 "janvier", "février", "mars", "avril", "mai", "juin",
 "juillet", "août", "septembre", "octobre", "novembre", "décembre"
// Requête : les_mois_ordonnes est de type IEnumerable<string>
var les_mois_ordonnes =
 from nom_du_mois in les_mois
 orderby nom_du_mois ascending
 select nom_du_mois;
// Exécution de la requête : itération sur les mois ordonnés
foreach (string mois in les_mois_ordonnes)
 Console.WriteLine("- {0}", mois );
// Affiche les mois dans l'ordre alphabétique :
// - août
// - avril
// - décembre
// - février
// - janvier
// - juillet
// - juin
// - mai
// - mars
// - novembre
// - octobre
// - septembre
Exemple avec un tableau d'objets utilisé dans une requête où second critère de tri est spécifié en cas d'égalité pour le premier :
// L'ensemble des données
public class VenteDuMois
List<VenteDuMois> ventes_par_mois = new List<VenteDuMois>
 new VenteDuMois { Mois = "janvier", Montants = new List<int> { 220, 158, 301 } },
 new VenteDuMois { Mois = "février", Montants = new List<int> { 162, 143, 157 } },
 new VenteDuMois { Mois = "mars", Montants = new List<int> { 138, 187, 231 } },
 new VenteDuMois { Mois = "avril", Montants = new List<int> { 11, 55, 400 } },
 new VenteDuMois { Mois = "mai", Montants = new List<int> { 311, 117, 90, 180 } },
// Requête : meilleurs_mois est de type IEnumerable<object>
var meilleurs_mois =
 from vente_du_mois in ventes_par_mois
 orderby vente_du_mois.Montants.Sum() descending, vente_du_mois.Name ascending
 select new { Name=vente_du_mois.Mois, Total=vente_du_mois.Montants.Sum() };
// Exécution de la requête : itération sur les meilleurs mois
foreach (string mois in meilleurs_mois)
 Console.WriteLine("- {0} => {1}", mois.Name, mois.Total );
// Affiche les mois dans l'ordre décroissant du total des montants :
// - mai => 698
// - janvier => 679
// - mars => 556
// - avril => 466
// - février => 462
Regroupement.
Le regroupement est introduit par le mot-clé codice_20 produisant une séquence d'objets de classe implémentant l'interface codice_7.
Cette interface permet d'accéder à la clé K commune aux éléments membres du groupe par la propriété codice_32, et étend l'interface codice_3.
Cela signifie qu'une instance de cette interface permet d'itérer sur les éléments membres du groupe.
Le mot-clé codice_20 est suivi de l'objet groupé (définissant T pour l'interface générique codice_7), du mot-clé codice_36 suivi de la clé de regroupement (définissant K pour l'interface générique codice_7).
Exemple : Regrouper les dates d'un planning annuel par mois
// L'ensemble des données
public class DateReunion
List<DateReunion> dates_planning = new List<DateReunion>
 new DateReunion { Mois = "janvier", jour = 22 },
 new DateReunion { Mois = "février", jour = 17 },
 new DateReunion { Mois = "mars", jour = 11 },
 new DateReunion { Mois = "avril", jour = 15 },
 new DateReunion { Mois = "janvier", jour = 12 },
 new DateReunion { Mois = "février", jour = 18 },
 new DateReunion { Mois = "mars", jour = 8 },
 new DateReunion { Mois = "avril", jour = 2 },
 new DateReunion { Mois = "janvier", jour = 26 },
 new DateReunion { Mois = "février", jour = 16 },
 new DateReunion { Mois = "mars", jour = 20 },
// Requête : planning_mensuel est de type IEnumerable<IGrouping<string,DateReunion»
var planning_mensuel =
 from date_reunion in dates_planning
 group date_reunion by date_reunion.Mois; // -> IGrouping<string,DateReunion>
Pour effectuer des opérations supplémentaires sur les groupes, il faut ajouter une clause codice_38 pour définir le nom référençant le groupe, comme dans l'exemple suivant :
// Requête : planning_mensuel est de type IEnumerable<IGrouping<string,DateReunion»
var planning_mensuel =
 from date_reunion in dates_planning
 group date_reunion by date_reunion.Mois into g // -> IGrouping<string,DateReunion>
 orderby g.Key // par mois dans l'ordre croissant
 select g;
Deux boucles imbriquées sont nécessaires : la boucle de premier niveau itère sur les groupes, et la boucle de second niveau itère sur les membres de chaque groupe, comme illustré ci-dessous :
// Exécution de la requête : itération sur les résultats
foreach (IGrouping<string,DateReunion> group in planning_mensuel)
 Console.WriteLine("Dates en {0} :", group.Key);
 foreach (DateReunion date in group)
 Console.WriteLine(" le {0} {1}", date.jour, date.Mois);
L'exemple affiche les dates groupées par mois :
La clé de regroupement est une expression quelconque, et peut créer un nouvel objet pour regrouper plusieurs critères de regroupement.
Combinaison de sources de données.
Jointure.
Il est possible de faire une jointure libre en utilisant plusieurs clauses codice_1 sur des sources de données indépendantes, comme dans l'exemple ci-dessous.
string[] projects = { "wikibooks", "wikinews", "wikiversity" };
string[] langs = { "fr", "es", "de" };
var project_domains =
 from project in projects
 where project != "wikinews" // sauf wikinews
 from lang in langs
 where project != "wikiversity" || lang != 'de' // sauf (wikiversity, de)
 select lang+"."+project+".org";
// Exécution de la requête :
foreach (string domain in project_domains)
 Console.WriteLine("- {0}", domain);
// Affiche :
// - fr.wikibooks.org
// - fr.wikiversity.org
// - es.wikibooks.org
// - es.wikiversity.org
// - de.wikibooks.org
Sous-requête.
Il est possible de créer une sous-requête pour sélectionner des données d'une collection stockée dans un objet.
Pour cela, une clause codice_1 est ajoutée à la première, référençant la variable de celle-ci.
Exemple :
// L'ensemble des données
public class VenteDuMois
List<VenteDuMois> ventes_par_mois = new List<VenteDuMois>
 new VenteDuMois { Mois = "janvier", Montants = new List<int> { 220, 158, 301 } },
 new VenteDuMois { Mois = "février", Montants = new List<int> { 162, 143, 157 } },
 new VenteDuMois { Mois = "mars", Montants = new List<int> { 138, 187, 231 } },
 new VenteDuMois { Mois = "avril", Montants = new List<int> { 11, 55, 400 } },
 new VenteDuMois { Mois = "mai", Montants = new List<int> { 311, 117, 90, 180 } },
// Requête : meilleurs_mois est de type IEnumerable<object>
var grands_montants =
 from vente_du_mois in ventes_par_mois
 from montant in vente_du_mois.Montants
 where montant >= 200
 select new { Name=vente_du_mois.Mois, Montant=montant };
// Exécution de la requête : itération sur les montants plus grands que 200
foreach (string mois in grands_montants)
 Console.WriteLine("- {0} => {1}", mois.Name, mois.Montant );
// Affiche les grands montants :
// - janvier => 220
// - janvier => 301
// - mars => 231
// - avril => 400
// - mai => 311