Partager via


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 System.Collections.Generic.IEnumerable<T> collections. Au moment de la compilation, la syntaxe de requête est convertie en appels de méthode vers l'implémentation des méthodes de requête standard du 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 prend un tableau de chaînes, les regroupe en fonction du premier caractère de la chaîne et trie les groupes.

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 étant fortement typées, tout comme les variables dont vous spécifiez explicitement le type. L'utilisation de var permet de créer des 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 collection permettent d’initialiser des objets sans appeler explicitement un constructeur pour l’objet. Les initialiseurs sont généralement utilisés dans les expressions de requête lorsqu’ils projetent les données sources dans un nouveau type de données. En supposant qu’une classe nommée Customer avec public Name et Phone propriétés, l’initialiseur d’objet peut être utilisé comme dans le code suivant :

var cust = new Customer { Name = "Mike", Phone = "555-1212" };

Poursuivez avec votre classe Customer, supposons qu’il existe une source de données appelée IncomingOrders, et que pour chaque commande avec un OrderSize important, vous souhaitez créer une nouvelle Customer basée sur cette commande. Une requête LINQ peut être exécutée sur cette source de données et utiliser l’initialisation d’objet 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 Customer classe, par OrderSizeexemple, mais avec l’initialisation de l’objet, les données retournées par la requête sont incorporées dans le type de données souhaité ; vous choisissez les données pertinentes pour votre classe. Par conséquent, vous disposez désormais d’un System.Collections.Generic.IEnumerable<T> contenant les nouveaux Customer que vous vouliez. L’exemple précédent peut également être écrit 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 :

Types anonymes

Le compilateur construit un type anonyme. Le nom du type est disponible uniquement pour le compilateur. Les types anonymes offrent un moyen pratique de regrouper temporairement un ensemble de propriétés 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 illustré 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, afin qu’elle puisse être appelée comme s’il s’agissait d’une méthode d’instance sur le type. Cette fonctionnalité vous permet, en effet, d’ajouter de nouvelles méthodes à des types existants sans les modifier réellement. 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 implémentant IEnumerable<T>.

Lambda Expressions

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 délégué ou en arborescence d’expressions. Dans la programmation LINQ, vous rencontrez des expressions lambda lorsque vous effectuez des appels de méthode directe 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 qui représentent des requêtes ne stockent pas la collection résultante, mais plutôt les étapes à suivre pour produire les résultats si nécessaire. L’avantage de renvoyer des objets de requête à partir de méthodes est qu’ils peuvent être composés ou modifiés. Par conséquent, toute valeur de retour ou out paramètre 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 concret List<T> ou Array, elle retourne les résultats de la requête au lieu de la requête elle-même. Une variable de requête retournée à partir d’une méthode peut toujours être composée ou modifiée.

Dans l’exemple suivant, la première méthode QueryMethod1 retourne une requête en tant que valeur de retour, et la deuxième méthode QueryMethod2 retourne une requête en tant que out paramètre (returnQ dans l’exemple). Dans les deux cas, il s’agit d’une requête retournée, et non de résultats de 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 QueryMethod1 directement, sans utiliser myQuery1.

foreach (var s in QueryMethod1(nums))
{
    Console.WriteLine(s);
}

Placez le pointeur de la souris sur l’appel à QueryMethod1 pour voir son type de retour.

QueryMethod2 retourne une requête comme valeur de son out paramètre :

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 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);
}