Partager via


Relations de type dans les 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 les unes avec les autres. La saisie forte est utilisée 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).

Capture d’écran montrant une requête pseudocode avec des éléments mis en surbrillance.

Le type de la variable de plage dans la requête doit être compatible avec le type des éléments de 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 Select clause. 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 type fort facilite l’identification des erreurs de type au moment de la compilation.

Visual Basic facilite la saisie forte en implémentant l’inférence de type local, également appelée saisie implicite. 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. Dans Visual Basic, l’inférence de type local est effectuée simplement à l’aide d’une Dim instruction sans As clause. Dans l’exemple suivant, city est fortement typé sous forme de chaîne.

Dim city = "Seattle"

Remarque

L’inférence de type local fonctionne uniquement lorsqu’elle Option Infer est définie sur On. Pour plus d’informations, consultez l’instruction Option Infer.

Toutefois, même si vous utilisez l’inférence de type local dans une requête, les mêmes relations de type sont présentes entre les variables de la source de données, la variable de requête et la boucle d’exécution de requête. Il est utile d’avoir une compréhension de base de ces relations de type lorsque vous écrivez des requêtes LINQ ou que vous travaillez avec les exemples et les exemples de code dans la documentation.

Vous devrez peut-être spécifier un type explicite pour une variable de plage qui ne correspond pas au type retourné par la source de données. Vous pouvez spécifier le type de la variable de plage à l’aide d’une As clause. Toutefois, cela entraîne une erreur si la conversion est une conversion restrictive et Option Strict est définie sur On. Par conséquent, nous vous recommandons d’effectuer 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 plage explicite à l’aide de la Cast méthode. Vous pouvez également convertir les valeurs sélectionnées dans la Select clause en un type explicite différent du type de la variable de plage. 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 sources

L’exemple suivant montre une opération de requête LINQ qui retourne une séquence d’éléments sélectionnés à partir des données sources. La source, namescontient un tableau de chaînes et la sortie de la requête est une séquence contenant des chaînes commençant 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 il est beaucoup plus court et plus facile à écrire. La dépendance vis-à-vis de l’inférence de type local dans les requêtes est le style préféré en Visual Basic.

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.

  1. Le type des éléments dans la source de données, namesest le type de la variable de plage, namedans la requête.

  2. Type de l’objet sélectionné, namedétermine le type de la variable de requête. mNames Voici name une chaîne, de sorte que la variable de requête est IEnumerable(Of String) en Visual Basic.

  3. La requête définie dans mNames est exécutée dans la For Each boucle. La boucle itère sur le résultat de l’exécution de la requête. Étant donné que mNames, lorsqu’il est exécuté, retourne une séquence de chaînes, la variable d’itération de boucle, nmégalement une chaîne.

Requêtes qui retournent un champ à partir d’éléments sélectionnés

L’exemple suivant montre 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 comme source de Customer données et projette uniquement la Name propriété dans le résultat. Étant donné que le nom du client est une chaîne, la requête produit une séquence de chaînes en tant que 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 similaires à celles de l’exemple plus simple.

  1. Le type des éléments dans la source de données, customersest le type de la variable de plage, custdans la requête. Dans cet exemple, ce type est Customer.

  2. L’instruction Select retourne la Name propriété de chaque Customer objet au lieu de l’objet entier. Comme Name il s’agit d’une chaîne, la variable de requête, custNamesest à nouveau IEnumerable(Of String), pas de Customer.

  3. Étant donné que custNames représente une séquence de chaînes, la variable d’itération de la For Each boucle, custNamedoit être une chaîne.

Sans inférence de type local, l’exemple précédent serait plus fastidieux à écrire et à comprendre, comme l’illustre 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 nécessitent des types anonymes

L’exemple suivant montre une situation plus complexe. Dans l’exemple précédent, il était peu pratique de spécifier des types pour toutes les variables explicitement. Dans cet exemple, il est impossible. Au lieu de sélectionner des éléments entiers Customer à partir de la source de données ou d’un champ unique à partir de chaque élément, la Select clause de cette requête retourne deux propriétés de l’objet d’origine Customer : Name et City. En réponse à la Select clause, le compilateur définit un type anonyme qui contient ces deux propriétés. Le résultat de l’exécution nameCityQuery dans la For Each boucle 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 le type ou nameCityQuerycustInfo explicitement. Autrement dit, avec un type anonyme, vous n’avez aucun nom de type à utiliser à la place de StringIEnumerable(Of String). Pour plus d’informations, consultez Types anonymes.

' 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

Bien qu’il ne soit pas possible de spécifier des types pour toutes les variables de l’exemple précédent, les relations restent identiques.

  1. Le type des éléments de la source de données est à nouveau le type de la variable de plage dans la requête. Dans cet exemple, cust est une instance de Customer.

  2. Étant donné que l’instruction Select produit un type anonyme, la variable de requête, nameCityQuerydoit être implicitement typée en tant que type anonyme. Un type anonyme n’a pas de nom utilisable et ne peut donc pas être spécifié explicitement.

  3. Le type de la variable d’itération dans la For Each boucle 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 boucle doit être déterminé implicitement.

Voir aussi