Cette rubrique propose une vue d'ensemble des fonctionnalités des génériques dans le .NET Framework et le Common Language Runtime, et notamment :
-
un résumé des types et des méthodes génériques et la terminologie employée pour ceux-ci ;
-
les classes de collection génériques dans les espaces de noms System.Collections.Generic et System.Collections.ObjectModel ;
-
les autres types génériques ;
-
les délégués génériques pour les conversions, les prédicats de recherche et les actions à effectuer sur les éléments d'un tableau ou d'une collection ;
-
les interfaces génériques fournissant des fonctionnalités communes à toutes les familles de types génériques.
Présentation des génériques, mode d'utilisation et définition de génériques
Les génériques sont des classes, des structures, des interfaces et des méthodes qui possèdent des espaces réservés (paramètres de type) pour un ou plusieurs des types qu'ils stockent ou utilisent. Une classe de collection générique peut utiliser un paramètre de type comme espace réservé du type d'objets qu'elle stocke ; les paramètres de type se présentent comme les types de ses champs et les types de paramètre de ses méthodes. Une méthode générique peut utiliser son paramètre de type en tant que type de sa valeur de retour ou en tant que type de l'un de ses paramètres formels. Le code suivant illustre une définition de classe générique simple.
Public Class Generic(Of T) Public Field As T End Class
public class Generic<T> { public T Field; }
generic<typename T> public ref class Generic { public: T Field; };
Lorsque vous créez une instance d'une classe générique, vous spécifiez les types à substituer aux paramètres de type. Vous créez ainsi une nouvelle classe générique, désignée par le terme « classe générique construite », les types que vous avez choisis étant substitués là où les paramètres de type apparaissent. Le résultat est une classe de type sécurisé adaptée à votre choix de types, comme l'illustre le code suivant.
Dim g As New Generic(Of String) g.Field = "A string"
Generic<string> g = new Generic<string>(); g.Field = "A string";
Generic<String^>^ g = gcnew Generic<String^>();
g->Field = "A string";
La terminologie utilisée pour les génériques dans le .NET Framework est la suivante :
-
Une définition de type générique est une déclaration de classe, de structure ou d'interface qui fonctionne comme un modèle, avec des espaces réservés pour les types qu'elle peut contenir ou utiliser. Par exemple, la classe Dictionary peut contenir deux types : des clés et des valeurs. Dans la mesure où il s'agit simplement d'un modèle, vous ne pouvez pas créer des instances d'une classe, d'une structure ou d'une interface qui représente une définition de type générique.
-
Les paramètres de type générique, ou paramètres de type, représentent les espaces réservés dans une définition de type ou de méthode générique. Le type générique Dictionary possède deux paramètres de type, TKey et TValue, représentant les types de ses clés et de ses valeurs.
-
Un type générique construit, ou type construit, est le résultat de la spécification de types pour les paramètres de type générique d'une définition de type générique.
-
Un argument de type générique représente tout type substitué à un paramètre de type générique.
-
Le terme général « type générique » comprend à la fois des types construits et des définitions de type générique.
-
Les contraintes sont des limites placées sur les paramètres de type générique. Par exemple, vous pouvez limiter un paramètre de type aux types qui implémentent l'interface générique IComparer, pour garantir que les instances du type puissent être classées. Vous pouvez également limiter les paramètres de type à des types possédant une classe de base particulière, un constructeur par défaut ou représentant des types référence ou des types valeur. Les utilisateurs du type générique ne peuvent pas substituer les arguments de type qui ne respectent pas les contraintes.
-
Une définition de méthode générique est une méthode avec deux listes de paramètres : une liste des paramètres de type générique et une liste des paramètres formels. Les paramètres de type peuvent apparaître sous la forme du type de retour ou des types des paramètres formels, comme l'illustre le code suivant.
Visual BasicFunction Generic(Of T)(ByVal arg As T) As T Dim temp As T = arg ... End Function
C#T Generic<T>(T arg) { T temp = arg; ...}C++generic<typename T> T Generic(T arg) { T temp = arg; ...};Les méthodes génériques peuvent apparaître sur des types génériques ou non génériques. Il est important de noter qu'une méthode n'est pas générique simplement en raison de son appartenance à un type générique, ou encore parce qu'elle a des paramètres formels dont les types sont les paramètres génériques du type englobant. Une méthode est générique uniquement si elle possède sa propre liste de paramètres de type. Dans le code suivant, seule la méthode G est générique.
Visual BasicClass A Function G(Of T)(ByVal arg As T) As T ... End Function End Class Class Generic(Of T) Function M(ByVal arg As T) As T ... End Function End Class
C#class A { T G<T>(T arg) {...} } class Generic<T> { T M(T arg) {...} }
C++ref class A { generic<T> T G(T arg) {...}; }; generic<typename T> ref class Generic { T M(T arg) {...}; };
Visual C++, C# et Visual Basic fournissent tous trois une prise en charge complète de la définition et de la consommation des génériques. Pour plus d'informations, consultez Types génériques en Visual Basic, Introduction aux génériques (guide de programmation C#) et Overview of Generics in C++.
Types imbriqués et génériques
Un type imbriqué dans un type générique peut dépendre des paramètres de type du type générique englobant, et de tels types imbriqués sont considérés comme étant génériques par le Common Language Runtime, même s'ils ne possèdent pas leurs propres paramètres de type générique. Lorsque vous créez une instance d'un type imbriqué, il est nécessaire de spécifier des arguments de type pour tous les types génériques englobants.
Collections génériques dans le .NET Framework
La bibliothèque de classes du .NET Framework fournit plusieurs classes de collection génériques, dans les espaces de noms System.Collections.Generic et System.Collections.ObjectModel. Pour plus d'informations sur ces classes, consultez Types de collections couramment utilisés.
System.Collections.Generic
Un grand nombre de types collection génériques sont des équivalents directs de types non génériques. Dictionary est une version générique de Hashtable ; il utilise la structure générique KeyValuePair pour l'énumération au lieu de DictionaryEntry.
List est une version générique de ArrayList. Il existe des classes Queue et Stack génériques qui correspondent aux versions non génériques.
Il existe des versions génériques et non génériques de SortedList, lesquelles sont toutes deux des hybrides entre un dictionnaire et une liste, et présentent des performances similaires. La classe générique SortedDictionary est un dictionnaire à part entière, dont les performances sont différentes, et qui ne possède aucun équivalent non générique.
La classe générique LinkedList est une véritable liste liée. Elle n'a aucun équivalent non générique.
System.Collections.ObjectModel
La classe générique Collection fournit une classe de base destinée à dériver vos propres types collection génériques. La classe ReadOnlyCollection offre un moyen facile de créer une collection en lecture seule à partir de n'importe quel type implémentant l'interface générique IList. La classe générique KeyedCollection permet de stocker des objets qui contiennent leurs propres clés.
Autres types génériques
La structure générique Nullable permet d'utiliser des types valeur comme s'il était possible de leur assigner null. Cela peut s'avérer utile lors de l'utilisation de requêtes de base de données, dont certains champs contenant des types valeur sont parfois manquants. Le paramètre de type générique peut représenter n'importe quel type valeur.
Remarque |
|---|
| En C#, il n'est pas nécessaire d'utiliser explicitement Nullable dans la mesure où le langage possède une syntaxe pour les types nullables. |
La structure générique ArraySegment permet de délimiter une plage d'éléments dans un tableau unidimensionnel, de base zéro, d'un type quelconque. Le paramètre de type générique est le type des éléments du tableau.
Le délégué générique EventHandler rend inutile la déclaration d'un type délégué pour gérer des événements, si votre événement respecte le modèle de gestion des événements utilisé par le .NET Framework. Supposons, par exemple, que vous avez créé une classe MyEventArgs, dérivée de EventArgs, pour stocker les données relatives à votre événement. Vous pouvez déclarer l'événement comme suit :
Public Event MyEvent As EventHandler(Of MyEventArgs)
public event EventHandler<MyEventArgs> MyEvent;
public:
event EventHandler<MyEventArgs^>^ MyEvent;
Délégués génériques pour la manipulation de tableaux et de listes
Le délégué générique Action représente une méthode qui exécute une action quelconque sur un élément du type spécifié. Vous pouvez créer une méthode qui exécute l'action souhaitée sur l'élément, créer une instance du délégué Action pour représenter cette méthode puis passer le tableau et le délégué à la méthode générique statique System.Array.ForEach.Action{. La méthode est appelée pour chaque élément du tableau.
La classe générique List fournit également une méthode ForEach qui utilise le délégué Action. Cette méthode n'est pas générique.
Remarque |
|---|
| À cet égard, il est intéressant de noter le point suivant sur les types et les méthodes génériques. La méthode System.Array.ForEach.Action{ doit être statique (Shared en Visual Basic) et générique, car Array n'est pas un type générique ; le fait que la méthode possède sa propre liste de paramètre de type est la seule raison vous permettant de spécifier un type sur lequel System.Array.ForEach.Action{ agit. En revanche, la méthode System.Collections.Generic.List.ForEach(System.Action{ non générique appartient à la classe générique List et utilise donc simplement le paramètre de type de sa classe. La classe étant fortement typée, la méthode peut être une méthode d'instance. |
Le délégué générique Predicate représente une méthode qui détermine si un élément particulier répond à des critères que vous définissez. Vous pouvez l'utiliser avec les méthodes génériques statiques suivantes de Array pour rechercher un élément ou un ensemble d'éléments : Exists, Find, FindAll, FindIndex, FindLast, FindLastIndex et TrueForAll.
Predicate fonctionne également avec les méthodes d'instance non génériques correspondantes de la classe générique List.
Le délégué générique Comparison vous permet de fournir un ordre de tri pour des éléments de tableau ou de liste sans ordre de tri natif ou encore de substituer l'ordre de tri natif. Créez une méthode qui effectue la comparaison, créez une instance du délégué Comparison pour représenter votre méthode, puis passez le tableau et le délégué à la méthode générique statique System.Array.Sort.Comparison{. La classe générique List fournit une méthode surchargée de l'instance correspondante, System.Collections.Generic.List.Sort(System.Comparison{.
Le délégué générique Converter vous permet de définir une conversion entre deux types et de convertir un tableau d'un type en un tableau de l'autre type ou encore de convertir une liste d'un type en une liste de l'autre type. Créez une méthode qui convertit les éléments de la liste existante dans le nouveau type, créez une instance de délégué pour représenter la méthode et utilisez la méthode statique générique System.Array.ConvertAll.Converter{ pour générer un tableau du nouveau type à partir du tableau d'origine ou la méthode d'instance générique System.Collections.Generic.List.ConvertAll.Converter{ pour générer une liste du nouveau type à partir de la liste d'origine.
Chaînage de délégués
Un grand nombre des méthodes qui utilisent ces délégués retournent un tableau ou une liste qui peut être passé à une autre méthode. Si, par exemple, vous souhaitez sélectionner certains éléments d'un tableau, les convertir en un nouveau type puis les enregistrer dans un nouveau tableau, vous pouvez passer le tableau retourné par la méthode générique FindAll à la méthode générique ConvertAll. Si le nouveau type d'élément ne dispose pas d'un ordre de tri natif, vous pouvez passer le tableau retourné par la méthode générique ConvertAll à la méthode générique Sort.
Interfaces génériques
Les interfaces génériques fournissent des équivalents de type sécurisé aux interfaces non génériques pour les comparaisons de classement et d'égalité de même que pour les fonctionnalités partagées par les types collection génériques.
Comparaisons d'égalité et de classement
Dans l'espace de noms System, les interfaces génériques System.IComparable et System.IEquatable, à l'instar de leurs équivalents non génériques, définissent des méthodes pour effectuer respectivement des comparaisons de classement et d'égalité. Les types implémentent ces interfaces pour permettre d'effectuer de telles comparaisons.
Dans l'espace de noms System.Collections.Generic, les interfaces génériques IComparer et IEqualityComparer offrent la possibilité de définir une comparaison de classement ou d'égalité pour les types qui n'implémentent pas l'interface générique System.IComparable ou System.IEquatable et permettent de redéfinir ces relations pour les types qui les implémentent. Ces interfaces sont utilisées par des méthodes et des constructeurs de nombreuses classes de collection génériques. Par exemple, vous pouvez passer un IComparer générique au constructeur de la classe SortedDictionary afin de spécifier un ordre de tri pour un type qui n'implémente pas l'interface System.IComparable générique. Il existe des surcharges de la méthode statique générique System.Array.Sort et de la méthode d'instance System.Collections.Generic.List.Sort(System.Collections.Generic.IComparer{ pour trier des tableaux et des listes à l'aide d'implémentations de IComparer génériques.
Les classes génériques Comparer et EqualityComparer fournissent des classes de base pour les implémentations des interfaces génériques IComparer et IEqualityComparer. Elles fournissent des comparaisons de classement et d'égalité par défaut par l'intermédiaire de leurs propriétés System.Collections.Generic.Comparer.Default et System.Collections.Generic.EqualityComparer.Default respectives.
Fonctionnalités d'une collection
L'interface générique ICollection est l'interface de base pour les types collection génériques. Elle fournit les fonctionnalités de base permettant d'ajouter, de supprimer, de copier et d'énumérer des éléments. ICollection hérite à la fois de l'interface IEnumerable générique et de l'interface IEnumerable non générique.
L'interface générique IList étend l'interface générique ICollection avec des méthodes de récupération indexée.
L'interface générique IDictionary étend l'interface générique ICollection avec des méthodes de récupération de clés. Les types du dictionnaire générique dans la bibliothèque de classes de base du .NET Framework implémentent également l'interface IDictionary non générique.
L'interface générique IEnumerable fournit une structure d'énumérateurs génériques. L'interface générique IEnumerator implémentée par les énumérateurs génériques hérite de l'interface IEnumerator non générique et les membres MoveNext et Reset, qui ne dépendent pas du paramètre de type T, apparaissent uniquement sur l'interface non générique. Cela signifie que tout consommateur de l'interface non générique peut également utiliser l'interface générique.
Limitations des génériques
Les éléments suivants constituent certaines limitations des génériques dans le .NET Framework version 2.0 :
-
Les types génériques peuvent être dérivés de la plupart des classes de base, telles que MarshalByRefObject (et des contraintes peuvent être utilisées pour que les paramètres de type générique dérivent obligatoirement de classes de base, comme MarshalByRefObject), mais dans cette version finale, les types génériques liés au contexte ne sont pas prises en charge. Un type générique peut être dérivé de ContextBoundObject, mais toute tentative de création d'une instance de ce type provoque une TypeLoadException.
-
Les énumérations ne peuvent pas avoir de paramètres de type générique. Une énumération ne peut être générique qu'incidemment, par exemple parce qu'elle est imbriquée dans un type générique défini à l'aide de Visual Basic, C# ou C++. Pour plus d'informations, consultez Énumérations dans le système de type commun.
-
Les méthodes dynamiques légères ne peuvent pas être génériques. Pour plus d'informations sur les méthodes dynamiques, consultez Scénarios de méthodes dynamiques avec émission de réflexion.
-
Dans Visual Basic, C# et C++, un type imbriqué inclus dans un type générique ne peut pas être instancié sans que les types aient été assignés aux paramètres de type de tous les types englobants. En d'autres termes, un type imbriqué défini à l'aide de ces langages inclut les paramètres de type de tous ses types englobants. Cela permet d'utiliser les paramètres de type des types englobants dans les définitions de membre d'un type imbriqué. Pour plus d'informations, consultez « Types imbriqués » dans MakeGenericType.
Remarque Un type imbriqué qui est défini en émettant un code dans un assembly dynamique ou en utilisant Assembleur MSIL (Ilasm.exe) n'est pas requis pour inclure les paramètres de type de ses types englobants ; toutefois, dans ce cas, les paramètres de type ne sont, par la suite, pas dans la portée de la classe imbriquée.
Pour plus d'informations, consultez « Types imbriqués » dans MakeGenericType.
Voir aussi
Tâches
Comment : définir un type générique avec émission de réflexionRéférence
Introduction aux génériques (guide de programmation C#)System.Collections.Generic
System.Collections.ObjectModel
Concepts
Quand utiliser les collections génériquesTypes génériques en Visual Basic
Overview of Generics in C++
Autres ressources
Types de collections couramment utilisésRéflexion et types génériques
Outils (masquer)
S'enregistrer
Liste des Membres
Qui est en ligne?
FAQ