Relations des types dans des opérations de requête LINQ (C#)
Pour écrire efficacement des requêtes, vous devez comprendre comment les types des variables dans une opération de requête complète sont liés les uns aux autres. Si vous comprenez ces relations, vous comprendrez plus facilement les exemples de code et les échantillons LINQ dans la documentation. En outre, vous comprendrez ce qui se passe lorsque des variables sont implicitement typées en utilisant var
.
Les opérations de requête LINQ sont fortement typées dans la source de données, dans la requête elle-même et dans l’exécution de la requête. Le type des variables dans la requête doit être compatible avec le type des éléments dans la source de données, ainsi qu’avec le type de la variable d’itération dans l’instruction foreach
. Ce typage fort garantit l’interception des erreurs de type au moment de la compilation lorsqu’elles peuvent être corrigées avant que les utilisateurs ne les rencontrent.
Pour illustrer ces relations de types, la plupart des exemples qui suivent utilisent le typage explicite pour toutes les variables. Le dernier exemple montre comment les mêmes principes s’appliquent même si vous utilisez le typage implicite en tirant parti de var
.
Requêtes qui ne transforment pas les données sources
L’illustration suivante montre une opération de requête LINQ to Objects qui n’effectue aucune transformation des données. La source contient une séquence de chaînes et le résultat de la requête est également une séquence de chaînes.
- L’argument de type de la source de données détermine le type de la variable de portée.
- Le type de l’objet sélectionné détermine le type de la variable de requête. Ici,
name
est une chaîne. Par conséquent, la variable de requête est unIEnumerable<string>
. - La variable de requête fait l’objet d’une itération dans l’instruction
foreach
. Comme la variable de requête est une séquence de chaînes, la variable d’itération est également une chaîne.
Requêtes qui transforment les données sources
L’illustration suivante montre une opération de requête LINQ to SQL qui effectue une transformation simple des données. La requête accepte une séquence d’objets Customer
en entrée et sélectionne uniquement la propriété Name
dans le résultat. Comme Name
est une chaîne, la requête produit une séquence de chaînes en sortie.
- L’argument de type de la source de données détermine le type de la variable de portée.
- L’instruction
select
retourne la propriétéName
à la place de l’objetCustomer
complet. CommeName
est une chaîne, l’argument de type decustNameQuery
eststring
, et non pasCustomer
. - Comme
custNameQuery
est une séquence de chaînes, la variable d’itération de la boucleforeach
doit également être de typestring
.
L’illustration suivante montre une transformation légèrement plus complexe. L’instruction select
retourne un type anonyme qui capture seulement deux membres de l’objet Customer
original.
- L’argument de type de la source de données est toujours le type de la variable de portée dans la requête.
- Comme l’instruction
select
génère un type anonyme, la variable de requête doit être implicitement typée à l’aide devar
. - Comme le type de la variable de requête est implicite, la variable d’itération dans la boucle
foreach
doit également être implicite.
Laisser le compilateur déduire les informations de type
Vous devez comprendre les relations des types dans une opération de requête. Toutefois, vous avez la possibilité de laisser le compilateur faire tout le travail à votre place. Le mot clé var peut être utilisé pour toute variable locale dans une opération de requête. L’illustration suivante est similaire à l’exemple numéro 2 qui a été abordé précédemment. Toutefois, le compilateur fournit le type fort pour chaque variable dans l’opération de requête.
LINQ et types génériques (C#)
Les requêtes LINQ sont basées sur des types génériques. Vous ne devez pas avoir une connaissance approfondie des génériques avant de commencer à écrire des requêtes. Il peut cependant être important de comprendre deux concepts de base :
- Quand vous créez une instance d’une classe de collection générique comme List<T>, vous remplacez le « T » par le type des objets contenus dans la liste. Par exemple, une liste de chaînes est exprimée sous la forme
List<string>
, et une liste d’objetsCustomer
est exprimée sous la formeList<Customer>
. Une liste générique est fortement typée et offre de nombreux avantages par rapport aux collections qui stockent leurs éléments en tant que Object. Si vous essayez d’ajouter unCustomer
à unList<string>
, vous obtenez une erreur à la compilation. Il est facile d’utiliser des collections génériques, car vous ne devez pas effectuer un cast de type à l’exécution. - IEnumerable<T> est l’interface qui permet l’énumération des classes de collection génériques avec l’instruction
foreach
. Les classes de collection génériques prennent en charge IEnumerable<T> de la même façon que les classes de collection non génériques telles que ArrayList prennent en charge IEnumerable.
Pour plus d’informations sur les génériques, consultez Génériques.
Variables IEnumerable<T> dans les requêtes LINQ
Les variables de requête LINQ sont typées en tant que IEnumerable<T> ou un type dérivé tel que IQueryable<T>. Quand vous voyez une variable de requête typée en IEnumerable<Customer>
, cela signifie simplement que la requête génère à l’exécution une séquence de zéro ou plusieurs objets Customer
.
IEnumerable<Customer> customerQuery =
from cust in customers
where cust.City == "London"
select cust;
foreach (Customer customer in customerQuery)
{
Console.WriteLine($"{customer.LastName}, {customer.FirstName}");
}
Laisser le compilateur gérer les déclarations de type générique
Si vous préférez, vous pouvez éviter une syntaxe générique en utilisant le mot clé var. Le mot clé var
indique au compilateur d’inférer le type d’une variable de requête en examinant la source de données spécifiée dans la clause from
. L’exemple suivant génère le même code compilé que l’exemple précédent :
var customerQuery2 =
from cust in customers
where cust.City == "London"
select cust;
foreach(var customer in customerQuery2)
{
Console.WriteLine($"{customer.LastName}, {customer.FirstName}");
}
Le mot clé var
est utile quand le type de la variable est évident ou quand il est particulièrement important de spécifier explicitement des types génériques imbriqués, comme ceux qui sont produits par des requêtes de groupe. D’une façon générale, si vous utilisez var
, sachez qu’il peut rendre votre code plus difficile à lire par d’autres développeurs. Pour plus d’informations, consultez Variables locales implicitement typées.