Relations des types dans des opérations de requête (Visual Basic)
Les variables utilisées dans les opérations de requête LINQ (Language Integrated Query) sont fortement typées et doivent être compatibles l'une avec l'autre. Le typage fort est utilisé dans la source de données, dans la requête elle-même, et dans l'exécution de la requête. L'illustration suivante identifie les termes utilisés pour décrire une requête LINQ. Pour plus d'informations sur les parties d'une requête, consultez Opérations de requête de base (Visual Basic).
Parties d'une requête LINQ
Le type de la variable de portée dans la requête doit être compatible avec le type des éléments dans la source de données. Le type de la variable de requête doit être compatible avec l'élément de séquence défini dans la clause Select. Enfin, le type des éléments de séquence doit également être compatible avec le type de la variable de contrôle de boucle utilisée dans l'instruction For Each qui exécute la requête. Ce typage fort facilite l'identification des erreurs de type au moment de la compilation.
En implémentant l'inférence de type local, également connue sous le nom de type implicite, Visual Basic rend le typage plus pratique. Cette fonctionnalité est utilisée dans l'exemple précédent et vous verrez qu'elle est utilisée dans les exemples et la documentation LINQ. En Visual Basic, l'inférence de type local s'effectue en utilisant simplement une instruction Dim sans clause As. Dans l'exemple suivant, city est fortement typé comme chaîne (string).
Dim city = "Seattle"
Notes
L'inférence de type local fonctionne uniquement lorsque Option Infer a la valeur On. Pour plus d'informations, consultez Instruction Option Infer.
Toutefois, même si vous utilisez l'inférence de type local dans une requête, les mêmes relations de types sont présentes parmi les variables dans la source de données, la variable de requête et la boucle d'exécution de la requête. Il est utile de bien comprendre les notions fondamentales de ces relations de types lorsque vous écrivez des requêtes LINQ ou que vous utilisez les exemples et exemples de code dans la documentation.
Vous devrez peut-être spécifier un type explicite pour une variable de portée qui ne correspond pas au type retourné par la source de données. Vous pouvez spécifier le type de la variable de portée à l'aide d'une clause As. Toutefois, une erreur se produit si la conversion est une conversion restrictive et que Option Strict a la valeur On. Par conséquent, il est recommandé d'exécuter la conversion sur les valeurs récupérées à partir de la source de données. Vous pouvez convertir les valeurs de la source de données en type de variable de portée explicite à l'aide de la méthode Cast<TResult>. Vous pouvez également effectuer un cast des valeurs sélectionnées dans la clause Select vers un type explicite qui est différent du type de la variable de portée. Ces points sont illustrés dans le code suivant.
Dim numbers1() As Integer = {1, 2, 4, 16, 32, 64}
Dim numbers2() As Double = {5.0#, 10.0#, 15.0#}
' This code does not result in an error.
Dim numberQuery1 = From n As Integer In numbers1 Where n > 5
' This code results in an error with Option Strict set to On. The type Double
' cannot be implicitly cast as type Integer.
Dim numberQuery2 = From n As Integer In numbers2 Where n > 5
' This code casts the values in the data source to type Integer. The type of
' the range variable is Integer.
Dim numberQuery3 = From n In numbers2.Cast(Of Integer)() Where n > 5
' This code returns the value of the range variable converted to Integer. The type of
' the range variable is Double.
Dim numberQuery4 = From n In numbers2 Where n > 5 Select CInt(n)
Requêtes qui retournent des éléments entiers des données source
L'exemple suivant présente une opération de requête LINQ qui retourne une séquence d'éléments sélectionnés à partir des données source. La source, names, contient un tableau de chaînes, et le résultat de la requête est une séquence contenant des chaînes qui commencent par la lettre M.
Dim names = {"John", "Rick", "Maggie", "Mary"}
Dim mNames = From name In names
Where name.IndexOf("M") = 0
Select name
For Each nm In mNames
Console.WriteLine(nm)
Next
Cela équivaut au code suivant, mais est beaucoup plus court et plus facile écrire. Le style privilégié par Visual Basic est la fiabilité de l'inférence de type local dans les requêtes.
Dim names2 = {"John", "Rick", "Maggie", "Mary"}
Dim mNames2 As IEnumerable(Of String) =
From name As String In names
Where name.IndexOf("M") = 0
Select name
For Each nm As String In mNames
Console.WriteLine(nm)
Next
Les relations suivantes existent dans les deux exemples de code précédents, que les types soient déterminés implicitement ou explicitement.
Le type des éléments dans la source de données, names, est le type de la variable de portée, name, dans la requête.
Le type de l'objet sélectionné, name, détermine le type de la variable de requête, mNames. Ici, name est une chaîne, donc la variable de requête est IEnumerable(Of String) en Visual Basic.
La requête définie dans mNames est exécutée dans la boucle For Each. La boucle itère au sein du résultat de l'exécution de la requête. La variable d'itération de boucle, nm, est une chaîne, étant donné que mNames, retourne une séquence de chaînes lors de son exécution.
Requêtes qui retournent un champ d'éléments sélectionnés
L'exemple suivant présente une opération de requête LINQ to SQL qui retourne une séquence contenant une seule partie de chaque élément sélectionné à partir de la source de données. La requête prend une collection d'objets Customer comme sa source de données et projette uniquement la propriété Name dans le résultat. Étant donné que le nom de client est une chaîne, la requête produit une séquence de chaînes comme sortie.
' Method GetTable returns a table of Customer objects.
Dim customers = db.GetTable(Of Customer)()
Dim custNames = From cust In customers
Where cust.City = "London"
Select cust.Name
For Each custName In custNames
Console.WriteLine(custName)
Next
Les relations entre les variables sont identiques à celles de l'exemple simplifié.
Le type des éléments dans la source de données, customers, est le type de la variable de portée, cust, dans la requête. Dans cet exemple, ce type est Customer.
L'instruction Select retourne la propriété Name de chaque objet Customer au lieu de l'objet complet. Étant donné que Name est une chaîne, la variable de requête, custNames, sera à nouveau IEnumerable(Of String), et non Customer.
Étant donné que custNames représente une séquence de chaînes, la variable d'itération de boucle For Each, custName, doit être une chaîne.
Sans inférence de type local, l'exemple précédent serait plus fastidieux à écrire et à comprendre, comme le montre l'exemple suivant.
' Method GetTable returns a table of Customer objects.
Dim customers As Table(Of Customer) = db.GetTable(Of Customer)()
Dim custNames As IEnumerable(Of String) =
From cust As Customer In customers
Where cust.City = "London"
Select cust.Name
For Each custName As String In custNames
Console.WriteLine(custName)
Next
Requêtes qui requièrent des types anonymes
L'exemple suivant montre une situation plus complexe. Dans l'exemple précédent, il était fastidieux de spécifier explicitement des types pour toutes les variables. Dans cet exemple, c'est impossible. Au lieu de sélectionner des éléments Customer entiers de la source de données ou un champ unique de chaque élément, la clause Select dans cette requête retourne deux propriétés de l'objet Customer d'origine : Name et City. En réponse à la clause Select, le compilateur définit un type anonyme qui contient ces deux propriétés. Le résultat de l'exécution de nameCityQuery dans la boucle For Each est une collection d'instances du nouveau type anonyme. Étant donné que le type anonyme n'a pas de nom utilisable, vous ne pouvez pas spécifier explicitement le type de nameCityQuery ou custInfo. Autrement dit, avec un type anonyme, vous n'avez aucun nom de type à utiliser à la place de String dans IEnumerable(Of String). Pour plus d'informations, consultez Types anonymes (Visual Basic).
' Method GetTable returns a table of Customer objects.
Dim customers = db.GetTable(Of Customer)()
Dim nameCityQuery = From cust In customers
Where cust.City = "London"
Select cust.Name, cust.City
For Each custInfo In nameCityQuery
Console.WriteLine(custInfo.Name)
Next
Même s'il n'est pas possible de spécifier des types pour toutes les variables dans l'exemple précédent, les relations restent les mêmes.
Le type des éléments dans la source de données est encore le type de la variable de portée dans la requête. Dans cet exemple, cust est une instance de Customer.
Étant donné que l'instruction Select produit un type anonyme, la variable de requête, nameCityQuery, doit être implicitement typée comme type anonyme. Un type anonyme n'a pas de nom utilisable et ne peut donc pas être spécifié explicitement.
Le type de la variable d'itération de la boucle For Each est le type anonyme créé à l'étape 2. Étant donné que le type n'a pas de nom utilisable, le type de la variable d'itération de la boucle doit être déterminé implicitement.
Voir aussi
Concepts
Inférence de type local (Visual Basic)
Introduction à LINQ dans Visual Basic