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 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 :

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