Types génériques en Visual Basic (Visual Basic)
Un type générique est un élément de programmation unique qui s’adapte pour effectuer la même fonctionnalité pour plusieurs types de données. Lorsque vous définissez une classe ou une procédure générique, vous n’avez pas besoin de définir une version distincte pour chaque type de données pour lequel vous souhaiterez peut-être effectuer cette fonctionnalité.
Une analogie est un jeu de tournevis avec des têtes amovibles. Vous inspectez la vis et sélectionnez la tête correcte pour cette vis (barrée, croisée, en vedette). Une fois que vous insérez la tête correcte dans la poignée de tournevis, vous effectuez exactement la même fonction avec le tournevis, à savoir tourner la vis.
Lorsque vous définissez un type générique, vous le paramétrez avec un ou plusieurs types de données. Les paramètres de type permettent au code d’adapter les types de données à ses besoins. Votre code peut déclarer plusieurs éléments de programmation différents à partir de l’élément générique, chacun agissant sur un ensemble différent de types de données. Toutefois, les éléments déclarés effectuent toutes la logique identique, quels que soient les types de données qu’ils utilisent.
Par exemple, vous pouvez créer et utiliser une classe de file d’attente qui fonctionne sur un type de données spécifique tel que String
. Vous pouvez déclarer une telle classe à partir de System.Collections.Generic.Queue<T>, comme l’illustre l’exemple suivant.
Public stringQ As New System.Collections.Generic.Queue(Of String)
Vous pouvez désormais utiliser stringQ
pour travailler exclusivement avec des valeurs String
. Étant donné que stringQ
est spécifique à String
au lieu d’être généralisé pour les valeurs Object
, vous n’avez pas de liaison tardive ou de conversion de type. Les types génériques permettent d’économiser du temps d’exécution et de réduire les erreurs d’exécution.
Pour plus d’informations sur l’utilisation d’un type générique, consultez How to : Use a Generic Class.
Exemple de classe générique
L’exemple suivant montre une définition squelette d’une classe générique.
Public Class classHolder(Of t)
Public Sub processNewItem(ByVal newItem As t)
Dim tempItem As t
' Insert code that processes an item of data type t.
End Sub
End Class
Dans le squelette précédent, t
est un paramètre de type , c’est-à-dire un espace réservé pour un type de données que vous fournissez lorsque vous déclarez la classe. Ailleurs dans votre code, vous pouvez déclarer différentes versions de classHolder
en fournissant différents types de données pour t
. L’exemple suivant montre deux déclarations de ce type.
Public integerClass As New classHolder(Of Integer)
Friend stringClass As New classHolder(Of String)
Les déclarations précédentes déclarent les classes construites , dans lesquelles un type spécifique remplace le paramètre de type. Ce remplacement est propagé tout au long du code dans la classe construite. L’exemple suivant montre à quoi ressemble la procédure processNewItem
dans integerClass
.
Public Sub processNewItem(ByVal newItem As Integer)
Dim tempItem As Integer
' Inserted code now processes an Integer item.
End Sub
Pour obtenir un exemple plus complet, consultez Guide pratique pour définir une classe qui peut fournir des fonctionnalités identiques sur différents types de données.
Éléments de programmation éligibles
Vous pouvez définir et utiliser des classes génériques, des structures, des interfaces, des procédures et des délégués. .NET définit plusieurs classes, structures et interfaces génériques qui représentent des éléments génériques couramment utilisés. L’espace de noms System.Collections.Generic fournit des dictionnaires, des listes, des files d’attente et des piles. Avant de définir votre propre élément générique, vérifiez s’il est déjà disponible dans System.Collections.Generic.
Les procédures ne sont pas des types, mais vous pouvez définir et utiliser des procédures génériques. Consultez Generic Procedures in Visual Basic.
Avantages des types génériques
Un type générique sert de base pour déclarer plusieurs éléments de programmation différents, chacun fonctionnant sur un type de données spécifique. Les alternatives à un type générique sont les suivantes :
- Type unique fonctionnant sur le type de données
Object
. - Un ensemble de versions spécifiques du type. Chaque version est codée individuellement et fonctionne sur un type de données spécifique tel que
String
,Integer
ou un type défini par l’utilisateur tel quecustomer
.
Un type générique présente les avantages suivants par rapport à ces alternatives :
- Sécurité des types Les types génériques appliquent la vérification du type au moment de la compilation. Les types basés sur
Object
acceptent n’importe quel type de données et vous devez écrire du code pour vérifier si un type de données d’entrée est acceptable. Avec les types génériques, le compilateur peut intercepter les incompatibilités de type avant l’exécution. - Les performances. Les types génériques n'ont pas besoin d'encadrer et de désencadrer les données, car chacun d'entre eux est spécialisé dans un type de données. Les opérations basées sur
Object
doivent boxer les types de données d'entrée pour les convertir en types de donnéesObject
et déboxer les données destinées à la sortie. Les conversions boxing et unboxing réduisent les performances. Les types basés surObject
sont également à liaison tardive, ce qui signifie que l’accès à leurs membres nécessite du code supplémentaire au moment de l’exécution. Les conversions de types réduisent également les performances. - Consolidation du code Le code d’un type générique doit être défini une seule fois. Un ensemble de versions spécifiques au type d’un type doit répliquer le même code dans chaque version, avec la seule différence étant le type de données spécifique pour cette version. Avec les types génériques, les versions spécifiques au type sont toutes générées à partir du type générique d’origine.
- Réutilisation du code. Le code qui ne dépend pas d’un type de données particulier peut être réutilisé avec différents types de données s’il est générique. Vous pouvez souvent le réutiliser même avec un type de données que vous n’avez pas prédit à l’origine.
- Prise en charge de la communication en champ proche (IDE, Near Field Communication) Lorsque vous utilisez un type construit déclaré à partir d’un type générique, l’environnement de développement intégré (IDE) peut vous offrir une prise en charge supplémentaire pendant le développement de votre code. Par exemple, IntelliSense peut vous montrer les options spécifiques au type d’un argument à un constructeur ou à une méthode.
- Algorithmes génériques. Les algorithmes abstraits indépendants du type sont de bons candidats pour les types génériques. Par exemple, une procédure générique qui trie les éléments à l’aide de l’interface IComparable peut être utilisée avec n’importe quel type de données qui implémente IComparable.
Contraintes
Bien que le code d’une définition de type générique soit aussi indépendant que possible, vous devrez peut-être exiger une certaine fonctionnalité de tout type de données fourni à votre type générique. Par exemple, si vous souhaitez comparer deux éléments à trier ou à assembler, leur type de données doit implémenter l’interface IComparable. Vous pouvez appliquer cette exigence en ajoutant une contrainte au paramètre de type.
Exemple de contrainte
L’exemple suivant montre une définition squelette d’une classe avec une contrainte qui exige que l’argument de type implémente IComparable.
Public Class itemManager(Of t As IComparable)
' Insert code that defines class members.
End Class
Si le code suivant tente de construire une classe à partir de itemManager
fournissant un type qui n’implémente pas IComparable, le compilateur signale une erreur.
Types de contraintes
Votre contrainte peut spécifier les exigences suivantes dans n’importe quelle combinaison :
- L’argument de type doit implémenter une ou plusieurs interfaces
- L’argument de type doit être du même type ou hériter d'une seule classe au maximum.
- L’argument de type doit exposer un constructeur sans paramètre accessible au code qui crée des objets à partir de celui-ci
- L’argument de type doit être un type de référence , ou il doit s’agir d’un type valeur
Le code C# peut déclarer qu’un argument de type doit être un type non managé. Visual Basic applique cette contrainte pour le code Visual Basic qui utilise un type générique ou une méthode qui a été défini avec cette contrainte (en C#). Toutefois, vous ne pouvez pas déclarer de contrainte unmanaged
sur un paramètre de type en Visual Basic.
Si vous devez imposer plusieurs exigences, vous utilisez une liste de contraintes séparées par des virgules à l’intérieur des accolades ({ }
). Pour exiger un constructeur accessible, vous incluez le mot-clé New Operator dans la liste. Pour exiger un type de référence, vous incluez le mot clé Class
; pour exiger un type valeur, vous incluez le mot clé Structure
.
Pour plus d’informations sur les contraintes, consultez Liste de types.
Exemple de contraintes multiples
L’exemple suivant montre une définition squelette d’une classe générique avec une liste de contraintes sur le paramètre de type. Dans le code qui crée une instance de cette classe, l’argument de type doit implémenter à la fois les interfaces IComparable et IDisposable, être un type de référence et exposer un constructeur sans paramètre accessible.
Public Class thisClass(Of t As {IComparable, IDisposable, Class, New})
' Insert code that defines class members.
End Class
Termes importants
Les types génériques introduisent et utilisent les termes suivants :
- Type générique. Définition d’une classe, d’une structure, d’une interface, d’une procédure ou d’un délégué pour lequel vous fournissez au moins un type de données lorsque vous le déclarez.
- Paramètre de type. Dans une définition de type générique, un espace réservé pour un type de données que vous fournissez lorsque vous déclarez le type.
- Type Argument. Type de données spécifique qui remplace un paramètre de type lorsque vous déclarez un type construit à partir d’un type générique.
- Contrainte. Condition sur un paramètre de type qui limite l’argument de type que vous pouvez lui fournir. Une contrainte peut exiger que l’argument de type implémente une interface particulière, hérite d’une classe particulière, qu’il possède un constructeur sans paramètre accessible ou qu’il s’agisse d’un type référence ou d’un type valeur. Vous pouvez combiner ces contraintes, mais vous pouvez spécifier au maximum une classe de base.
- Type Construit. Classe, structure, interface, procédure ou délégué déclaré à partir d’un type générique en fournissant des arguments de type pour ses paramètres de type.