Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Lorsqu’un type ou une méthode générique est compilé en langage intermédiaire commun (CIL), il contient des métadonnées qui l’identifient comme ayant des paramètres de type. La façon dont la valeur CIL d’un type générique est utilisée diffère selon que le paramètre de type fourni est un type valeur ou un type référence.
Lorsqu’un type générique est construit pour la première fois avec un type valeur comme paramètre, l'environnement d'exécution crée un type générique spécialisé en substituant le ou les paramètres fournis aux emplacements appropriés dans la CIL. Les types génériques spécialisés sont créés une fois pour chaque type valeur unique utilisé comme paramètre.
Par exemple, supposons que votre code de programme a déclaré une pile construite d’entiers :
Stack<int>? stack;
À ce stade, le runtime génère une version spécialisée de la Stack<T> classe qui a l’entier remplacé de manière appropriée pour son paramètre. À présent, chaque fois que votre code de programme utilise une pile d’entiers, le runtime réutilise la classe spécialisée Stack<T> générée. Dans l’exemple suivant, deux instances d’une pile d’entiers sont créées et partagent une seule instance du Stack<int>
code :
Stack<int> stackOne = new Stack<int>();
Stack<int> stackTwo = new Stack<int>();
Toutefois, supposons qu’une autre Stack<T> classe avec un type valeur différent, tel qu'un long
ou une structure définie par l'utilisateur, soit créée à un autre point de votre code. Par conséquent, le runtime génère une autre version du type générique et remplace un long
dans les emplacements appropriés dans le CIL. Les conversions ne sont plus nécessaires, car chaque classe générique spécialisée contient en mode natif le type valeur.
Les génériques fonctionnent un peu différemment pour les types de référence. La première fois qu’un type générique est construit avec n’importe quel type de référence, le runtime crée un type générique spécialisé avec des références d’objet substituées aux paramètres dans la bibliothèque CIL. Ensuite, chaque fois qu’un type construit est instancié avec un type référence comme paramètre, quel que soit le type qu’il est, le runtime réutilise la version spécialisée créée précédemment du type générique. Cela est possible, car toutes les références sont de la même taille.
Par exemple, supposons que vous disposiez de deux types de référence, d’une Customer
classe et d’une Order
classe, et supposons également que vous avez créé une pile de Customer
types :
class Customer { }
class Order { }
Stack<Customer> customers;
À ce stade, le runtime génère une version spécialisée de la Stack<T> classe qui stocke les références d’objets qui seront renseignées ultérieurement au lieu de stocker des données. Supposons que la ligne de code suivante crée une pile d’un autre type de référence, nommé Order
:
Stack<Order> orders = new Stack<Order>();
Contrairement aux types valeur, une autre version spécialisée de la Stack<T> classe n’est pas créée pour le Order
type. Au lieu de cela, une instance de la version spécialisée de Stack<T> classe est créée et la variable est définie pour référencer orders
. Supposons que vous ayez rencontré ensuite une ligne de code pour créer une pile d’un type Customer
:
customers = new Stack<Customer>();
Comme avec l’utilisation précédente de la Stack<T> classe créée à l’aide du Order
type, une autre instance de la classe spécialisée Stack<T> est créée. Les pointeurs qui y sont contenus sont définis pour référencer une zone de mémoire de la taille d’un Customer
type. Étant donné que le nombre de types de référence peut varier d’un programme à l’autre, l’implémentation C# des génériques réduit considérablement la quantité de code en réduisant à un le nombre de classes spécialisées créées par le compilateur pour les classes génériques de types de référence.
De plus, lorsqu’une classe C# générique est instanciée à l’aide d’un type valeur ou d’un paramètre de type référence, la réflexion peut l’interroger au moment de l’exécution et à la fois son type réel et son paramètre de type peuvent être vérifiés.