Fonctionnalités C# qui prennent en charge LINQ
Expressions de requête
Les expressions de requête utilisent une syntaxe déclarative similaire à SQL ou XQuery pour interroger des collections System.Collections.Generic.IEnumerable<T>. Au moment de la compilation, la syntaxe de requête est convertie en appels de méthode à l’implémentation de méthodes de requête standard d’un fournisseur LINQ. Les applications contrôlent les opérateurs de requête standard qui se trouvent dans la portée en spécifiant l’espace de noms approprié avec une directive using
. L’expression de requête suivante accepte un tableau de chaînes, regroupe les chaînes qui commencent par le même caractère, puis trie ces groupes de chaînes.
var query = from str in stringArray
group str by str[0] into stringGroup
orderby stringGroup.Key
select stringGroup;
Variables implicitement typées (var)
Vous pouvez utiliser le modificateur var pour indiquer au compilateur de déduire et d’affecter le type, comme illustré ici :
var number = 5;
var name = "Virginia";
var query = from str in stringArray
where str[0] == 'm'
select str;
Les variables déclarées comme var
sont fortement typées, tout comme les variables dont vous spécifiez explicitement le type. L’utilisation de var
rend possible la création de types anonymes, mais uniquement pour les variables locales. Pour plus d’informations, consultez Variables locales implicitement typées.
Initialiseurs d’objets et de collections
Les initialiseurs d’objets et de collections permettent d’initialiser un objet sans appeler explicitement un constructeur pour cet objet. Les initialiseurs sont généralement utilisés dans les expressions de requête pour projeter la source de données en un nouveau type de données. En supposant une classe nommée Customer
avec les propriétés publiques Name
et Phone
, l’initialiseur d’objet peut être utilisé, comme dans le code suivant :
var cust = new Customer { Name = "Mike", Phone = "555-1212" };
Reprenez votre classe Customer
et supposez qu’il existe une source de données appelée IncomingOrders
et que, pour chaque commande caractérisée par un grand OrderSize
, vous souhaitez créer un nouveau Customer
basé sur cette commande. Une requête LINQ peut être exécutée sur cette source de données et utiliser l’initialisation d’objets pour remplir une collection :
var newLargeOrderCustomers = from o in IncomingOrders
where o.OrderSize > 5
select new Customer { Name = o.Name, Phone = o.Phone };
La source de données peut avoir plus de propriétés définies que la classe Customer
, par exemple, OrderSize
. Cependant, avec l’initialisation d’objets, les données retournées par la requête sont moulées dans le type de données souhaité ; vous choisissez les données correspondant à votre classe. Par conséquent, vous disposez désormais d’un System.Collections.Generic.IEnumerable<T> contenant les nouveaux Customer
que vous souhaitiez. L’exemple précédent peut également s’écrire dans la syntaxe de méthode LINQ :
var newLargeOrderCustomers = IncomingOrders.Where(x => x.OrderSize > 5).Select(y => new Customer { Name = y.Name, Phone = y.Phone });
À compter de C# 12, vous pouvez utiliser une expression de collection pour initialiser une collection.
Pour plus d’informations, consultez l’article suivant :
- Initialiseurs d’objets et de collections
- Syntaxe des expressions de requête pour les opérateurs de requête standard
Types anonymes
Le compilateur construit un type anonyme. Le nom du type est accessible uniquement au compilateur. Les types anonymes permettent de regrouper facilement des propriétés de manière temporaire dans un résultat de requête, sans avoir à définir un type nommé distinct. Les types anonymes sont initialisés avec une nouvelle expression et un initialiseur d’objet, comme indiqué ici :
select new {name = cust.Name, phone = cust.Phone};
À compter de C# 7, vous pouvez utiliser des tuples pour créer des types sans nom.
Méthodes d’extension
Une méthode d’extension est une méthode statique qui peut être associée à un type, de manière à pouvoir être appelée comme s’il s’agissait d’une méthode d’instance de ce type. Cette fonctionnalité permet d’ajouter de nouvelles méthodes aux types existants sans les modifier. Les opérateurs de requête standard sont un ensemble de méthodes d’extension qui fournissent des fonctionnalités de requête LINQ pour tout type qui implémente IEnumerable<T>.
Expressions lambda
Une expression lambda est une fonction inline qui utilise l’opérateur =>
pour séparer les paramètres d’entrée du corps de la fonction, et qui peut être convertie au moment de la compilation en un délégué ou une arborescence d’expressions. En programmation LINQ, vous rencontrerez des expressions lambda quand vous effectuerez des appels de méthode directs aux opérateurs de requête standard.
Expressions en tant que données
Les objets de requête sont composables, ce qui signifie que vous pouvez retourner une requête à partir d’une méthode. Les objets représentant des requêtes ne stockent pas la collection résultante, mais plutôt les étapes pour générer les résultats lorsque cela est nécessaire. L’avantage de retourner des objets de requête à partir de méthodes est qu’il est possible de les composer ou modifier encore. Par conséquent, toute valeur de retour ou paramètre out
d’une méthode qui retourne une requête doit également avoir ce type. Si une méthode matérialise une requête en un type List<T> ou Array concret, elle retourne les résultats de la requête plutôt que la requête elle-même. Une variable de requête retournée à partir d’une méthode peut encore être composée ou modifiée.
Dans l’exemple suivant, la première méthode QueryMethod1
retourne une requête comme valeur de retour et la seconde méthode QueryMethod2
retourne une requête comme paramètre out
(returnQ
dans l’exemple). Dans les deux cas, une requête est retournée, pas les résultats de la requête.
IEnumerable<string> QueryMethod1(int[] ints) =>
from i in ints
where i > 4
select i.ToString();
void QueryMethod2(int[] ints, out IEnumerable<string> returnQ) =>
returnQ = from i in ints
where i < 4
select i.ToString();
int[] nums = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
var myQuery1 = QueryMethod1(nums);
La requête myQuery1
est exécutée dans la boucle foreach suivante.
foreach (var s in myQuery1)
{
Console.WriteLine(s);
}
Placez le pointeur de la souris sur myQuery1
pour voir son type.
Vous pouvez également exécuter la requête retournée depuis QueryMethod1
directement, sans utiliser myQuery1
.
foreach (var s in QueryMethod1(nums))
{
Console.WriteLine(s);
}
Placez le pointeur de la souris sur l’appel pour QueryMethod1
voir son type de retour.
QueryMethod2
retourne une requête comme valeur de son paramètre out
:
QueryMethod2(nums, out IEnumerable<string> myQuery2);
// Execute the returned query.
foreach (var s in myQuery2)
{
Console.WriteLine(s);
}
Vous pouvez modifier une requête à l’aide de la composition de requête. Dans ce cas, l’objet de requête précédent est utilisé pour créer un nouvel objet de requête. Ce nouvel objet retourne des résultats différents de ceux de l’objet de requête d’origine.
myQuery1 = from item in myQuery1
orderby item descending
select item;
// Execute the modified query.
Console.WriteLine("\nResults of executing modified myQuery1:");
foreach (var s in myQuery1)
{
Console.WriteLine(s);
}