Types anonymes (Visual Basic)

Visual Basic prend en charge les types anonymes, ce qui permet de créer des objets sans écrire de définition de classe pour le type de données. À la place, le compilateur se charge de générer une classe. La classe ne possède pas de nom utilisable, hérite directement de Object et contient les propriétés que vous spécifiez lors de la déclaration de l'objet. Étant donné que le nom du type de données n’est pas spécifié, il est appelé type anonyme.

L’exemple suivant déclare et crée une variable product en tant qu’instance d’un type anonyme qui a deux propriétés, Name et Price.

' Variable product is an instance of a simple anonymous type.
Dim product = New With {Key .Name = "paperclips", .Price = 1.29}

Une expression de requête utilise des types anonymes pour combiner des colonnes de données sélectionnées par une requête. Vous ne pouvez pas définir le type du résultat à l’avance, car vous ne pouvez pas prédire les colonnes qu’une requête particulière peut sélectionner. Les types anonymes vous permettent d’écrire une requête qui sélectionne n’importe quel nombre de colonnes, dans n’importe quel ordre. Le compilateur crée un type de données qui correspond aux propriétés spécifiées et à l’ordre spécifié.

Dans les exemples suivants, products est une liste d’objets de produit, chacun ayant de nombreuses propriétés. La variable namePriceQuery contient la définition d’une requête qui, lorsqu’elle est exécutée, retourne une collection d’instances d’un type anonyme qui a deux propriétés,Name et Price.

Dim namePriceQuery = From prod In products
                     Select prod.Name, prod.Price

La variable nameQuantityQuery contient la définition d’une requête qui, lorsqu’elle est exécutée, retourne une collection d’instances d’un type anonyme qui a deux propriétés,Name et OnHand.

Dim nameQuantityQuery = From prod In products
                        Select prod.Name, prod.OnHand

Pour plus d’informations sur le code créé par le compilateur pour un type anonyme, consultez Définition de type anonyme.

Attention

Le nom du type anonyme est généré par le compilateur et peut varier d'une compilation à l'autre. Votre code ne doit pas utiliser ou s’appuyer sur le nom d’un type anonyme, car le nom peut changer lorsqu’un projet est recompilé.

Déclaration d’un type anonyme

La déclaration d’une instance d’un type anonyme utilise une liste d’initialiseurs pour spécifier les propriétés du type. Vous pouvez spécifier uniquement des propriétés lorsque vous déclarez un type anonyme, et non d’autres éléments de classe tels que des méthodes ou des événements. Dans l’exemple suivant, product1 est une instance d’un type anonyme qui a deux propriétés : Name et Price.

' Variable product1 is an instance of a simple anonymous type.
Dim product1 = New With {.Name = "paperclips", .Price = 1.29}
' -or-
' product2 is an instance of an anonymous type with key properties.
Dim product2 = New With {Key .Name = "paperclips", Key .Price = 1.29}

Si vous désignez des propriétés en tant que propriétés de clé, vous pouvez les utiliser pour comparer l'égalité de deux instances de types anonymes. Toutefois, les valeurs des propriétés de clé ne peuvent pas être modifiées. Pour plus d’informations, consultez la section Propriétés clés plus loin dans cette rubrique.

Notez que la déclaration d’une instance d’un type anonyme est semblable à la déclaration d’une instance d’un type nommé à l’aide d’un initialiseur d’objet :

' Variable product3 is an instance of a class named Product.
Dim product3 = New Product With {.Name = "paperclips", .Price = 1.29}

Pour plus d’informations sur d’autres façons de spécifier des propriétés de type anonyme, consultez Comment : déduire les types et les noms de propriétés dans des déclarations de types anonymes.

Propriétés de clé

Les propriétés clés diffèrent des propriétés non clés de plusieurs façons fondamentales :

  • Seules les valeurs des propriétés de clé sont comparées pour déterminer si deux instances sont égales.

  • Les valeurs des propriétés de clé sont en lecture seule et ne peuvent pas être modifiées.

  • Seules les valeurs de propriété de clé sont incluses dans l’algorithme de code de hachage généré par le compilateur pour un type anonyme.

Égalité

Les instances de types anonymes ne peuvent être égales que si elles sont des instances du même type anonyme. Le compilateur traite deux instances comme des instances du même type si elles remplissent les conditions suivantes :

  • Elles sont déclarées dans le même assembly.

  • Leurs propriétés ont les mêmes noms, les mêmes types inférés et sont déclarées dans le même ordre. Les comparaisons de noms ne respectent pas la casse.

  • Les mêmes propriétés dans chacune d’elles sont marquées comme propriétés de clé.

  • Au moins une propriété dans chaque déclaration est une propriété de clé.

Une instance d’un type anonyme qui n’a aucune propriété de clé n’est égale qu’à elle-même.

' prod1 and prod2 have no key values.
Dim prod1 = New With {.Name = "paperclips", .Price = 1.29}
Dim prod2 = New With {.Name = "paperclips", .Price = 1.29}

' The following line displays False, because prod1 and prod2 have no
' key properties.
Console.WriteLine(prod1.Equals(prod2))

' The following statement displays True because prod1 is equal to itself.
Console.WriteLine(prod1.Equals(prod1))

Deux instances du même type anonyme sont égales si les valeurs de leurs propriétés de clé sont égales. Les exemples suivants illustrent la façon dont l’égalité est testée.

Dim prod3 = New With {Key .Name = "paperclips", Key .Price = 1.29}
Dim prod4 = New With {Key .Name = "paperclips", Key .Price = 1.29}
' The following line displays True, because prod3 and prod4 are
' instances of the same anonymous type, and the values of their
' key properties are equal.
Console.WriteLine(prod3.Equals(prod4))

Dim prod5 = New With {Key .Name = "paperclips", Key .Price = 1.29}
Dim prod6 = New With {Key .Name = "paperclips", Key .Price = 1.29,
                      .OnHand = 423}
' The following line displays False, because prod5 and prod6 do not 
' have the same properties.
Console.WriteLine(prod5.Equals(prod6))

Dim prod7 = New With {Key .Name = "paperclips", Key .Price = 1.29,
                      .OnHand = 24}
Dim prod8 = New With {Key .Name = "paperclips", Key .Price = 1.29,
                      .OnHand = 423}
' The following line displays True, because prod7 and prod8 are
' instances of the same anonymous type, and the values of their
' key properties are equal. The equality check does not compare the
' values of the non-key field.
Console.WriteLine(prod7.Equals(prod8))

Valeurs en lecture seule

Les valeurs des propriétés de clé ne peuvent pas être modifiées. Par exemple, dans prod8 dans l’exemple précédent, les champs Name et Price sont read-only, mais OnHand peut être modifié.

' The following statement will not compile, because Name is a key
' property and its value cannot be changed.
' prod8.Name = "clamps"

' OnHand is not a Key property. Its value can be changed.
prod8.OnHand = 22

Types anonymes à partir d’expressions de requête

Les expressions de requête ne nécessitent pas toujours la création de types anonymes. Dans la mesure du possible, elles utilisent un type existant pour contenir les données de la colonne. Cela se produit lorsque la requête renvoie soit des enregistrements entiers de la source de données, soit un seul champ de chaque enregistrement. Dans les exemples de code suivants, customers est une collection d’objets d’une classe Customer. La classe possède de nombreuses propriétés, et vous pouvez inclure une ou plusieurs d'entre elles dans le résultat de la requête, dans n'importe quel ordre. Dans les deux premiers exemples, aucun type anonyme n’est requis, car les requêtes sélectionnent des éléments de types nommés :

  • custs1 contient une collection de chaînes, car cust.Name est une chaîne.

    Dim custs1 = From cust In customers
                 Select cust.Name
    
  • custs2 contient une collection d’objets Customer, car chaque élément de customers est un objet Customer, et l’élément entier est sélectionné par la requête.

    Dim custs2 = From cust In customers
                 Select cust
    

Toutefois, les types nommés appropriés ne sont pas toujours disponibles. Il se peut que vous souhaitiez sélectionner les noms et adresses des clients pour un objectif donné, leurs numéros d'ID et leur localisation pour un autre, et leurs noms, adresses et historiques de commandes pour un troisième. Les types anonymes vous permettent de sélectionner n'importe quelle combinaison de propriétés, dans n'importe quel ordre, sans avoir à déclarer au préalable de nouveau type nommé pour contenir le résultat. Au lieu de cela, le compilateur crée un type anonyme pour chaque compilation de propriétés. La requête suivante sélectionne uniquement le nom et le numéro d’ID du client à partir de chaque objet Customer dans customers. Par conséquent, le compilateur crée un type anonyme qui contient uniquement ces deux propriétés.

Dim custs3 = From cust In customers
             Select cust.Name, cust.ID

Les noms et les types de données des propriétés dans le type anonyme sont extraits des arguments vers Select, cust.Name et cust.ID. Les propriétés d’un type anonyme créé par une requête sont toujours des propriétés de clés. Lorsque custs3 est exécuté dans la boucle For Each suivante, le résultat est une collection d’instances d’un type anonyme avec deux propriétés de clé, Name et ID.

For Each selectedCust In custs3
    Console.WriteLine(selectedCust.ID & ": " & selectedCust.Name)
Next

Les éléments de la collection représentés par custs3 sont fortement typés, et vous pouvez utiliser IntelliSense pour parcourir les propriétés disponibles et vérifier leurs types.

Pour plus d’informations, consultez Introduction aux requêtes LINQ dans Visual Basic.

Décider s’il faut utiliser des types anonymes

Avant de créer un objet en tant qu’instance d’une classe anonyme, demandez-vous si c'est la meilleure option. Par exemple, si vous souhaitez créer un objet temporaire contenant des données associées et que vous n’avez pas besoin d’autres champs et méthodes qu’une classe complète peut contenir, un type anonyme est une bonne solution. Les types anonymes sont également pratiques si vous souhaitez une sélection différente de propriétés pour chaque déclaration, ou si vous souhaitez modifier l’ordre des propriétés. Toutefois, si votre projet inclut plusieurs objets qui ont les mêmes propriétés, dans un ordre fixe, vous pouvez les déclarer plus facilement à l’aide d’un type nommé avec un constructeur de classe. Par exemple, avec un constructeur approprié, il est plus facile de déclarer plusieurs instances d’une classe Product que de déclarer plusieurs instances d’un type anonyme.

' Declaring instances of a named type.
Dim firstProd1 As New Product("paperclips", 1.29)
Dim secondProd1 As New Product("desklamp", 28.99)
Dim thirdProd1 As New Product("stapler", 5.09)

' Declaring instances of an anonymous type.
Dim firstProd2 = New With {Key .Name = "paperclips", Key .Price = 1.29}
Dim secondProd2 = New With {Key .Name = "desklamp", Key .Price = 28.99}
Dim thirdProd2 = New With {Key .Name = "stapler", Key .Price = 5.09}

Un autre avantage des types nommés est que le compilateur peut intercepter une mauvaise saisie accidentelle d’un nom de propriété. Dans les exemples précédents, firstProd2, secondProd2et thirdProd2 sont censés être des instances du même type anonyme. Toutefois, si vous deviez déclarer thirdProd2 accidentellement de l’une des façons suivantes, son type serait différent de celui de firstProd2 et secondProd2.

' Dim thirdProd2 = New With {Key .Name = "stapler", Key .Price = 5.09}
' Dim thirdProd2 = New With {Key .Name = "stapler", Key .Price = "5.09"}
' Dim thirdProd2 = New With {Key .Name = "stapler", .Price = 5.09}

Plus important encore, il existe des limitations sur l’utilisation de types anonymes qui ne s’appliquent pas aux instances de types nommés. firstProd2, secondProd2et thirdProd2 sont des instances du même type anonyme. Toutefois, le nom du type anonyme partagé n’est pas disponible et ne peut pas apparaître où un nom de type est attendu dans votre code. Par exemple, un type anonyme ne peut pas être utilisé pour définir une signature de méthode, déclarer une autre variable ou un champ, ou dans une déclaration de type. Par conséquent, les types anonymes ne sont pas appropriés lorsque vous devez partager des informations entre les méthodes.

Une définition de type anonyme

En réponse à la déclaration d’une instance d’un type anonyme, le compilateur crée une définition de classe qui contient les propriétés spécifiées.

Si le type anonyme contient au moins une propriété de clé, la définition remplace trois membres hérités de Object : Equals, GetHashCodeet ToString. Le code produit pour tester l’égalité et déterminer la valeur du code de hachage considère uniquement les propriétés de clé. Si le type anonyme ne contient aucune propriété de clé, seul ToString est substitué. Les propriétés nommées explicitement d’un type anonyme ne peuvent pas entrer en conflit avec ces méthodes générées. Autrement dit, vous ne pouvez pas utiliser .Equals, .GetHashCode ou .ToString pour nommer une propriété.

Les définitions de type anonyme qui ont au moins une propriété de clé implémentent également l’interface System.IEquatable<T>, où T est le type du type anonyme.

Pour plus d’informations sur le code créé par le compilateur et les fonctionnalités des méthodes substituées, consultez Définition de type anonyme.

Voir aussi