Pourquoi utiliser des génériques C# ?
Afin de comprendre ce problème, examinons d'abord le code suivant. Le code omet du contenu, mais la fonction consiste à implémenter une pile, qui ne peut gérer que l'int. type de données :
public class Stack { This.m_item = new int[i]; } } Le code ci-dessus fonctionne très bien, mais que devons-nous faire lorsque nous avons besoin d'une pile pour enregistrer le type de chaîne ? Beaucoup de gens penseront à copier le code ci-dessus et à changer int en chaîne. Bien sûr, il n'y a rien de mal à faire cela en soi, mais un bon programme ne le fera pas parce qu'il réfléchit à ce qu'il doit faire s'il a à nouveau besoin d'une pile de type long ou Node à l'avenir ? Voulez-vous copier à nouveau ? Un bon programmeur pensera à utiliser un objet de type de données commun pour implémenter cette pile :
public class Stack { ){...} public Stack(int i) { this.m_item = new[i]; La pile est bien écrite. Elle est très flexible et peut recevoir n'importe quel type de données. On peut dire que c'est fait une fois pour toutes. Mais dans l'ensemble, ce n'est pas sans défauts, qui se manifestent principalement par :
Lorsque Stack gère les types de valeur, des opérations de boxing et de boxing se produiront, qui alloueront et recycleront un grand nombre de variables sur le tas géré. la quantité de données est importante, la perte de performances sera très grave.
Lorsqu'il s'agit de types de référence, bien qu'il n'y ait pas d'opération de boxing ou de pliage, l'opération de conversion forcée du type de données sera utilisée, ce qui augmente la charge du processeur.
Il existe des problèmes plus graves avec la coercition des types de données (en supposant que la pile est une instance de Stack) :
Node1 x = new Node2 y = (Node2)stack.Pop() ; ; Le code ci-dessus est tout à fait correct lors de la compilation, mais comme les données de type Node1 sont poussées, elles doivent être converties en type Node2 lors de Pop, ce qui entraînera l'exécution du programme à ce moment-là, mais cela. a échappé au contrôle du compilateur.
Pour résoudre le problème de la pile de types d'objets, nous introduisons des génériques, qui peuvent résoudre ces problèmes avec élégance. Les génériques utilisent un type de données transmis T au lieu d'un objet. Le type de T est spécifié lorsque la classe est instanciée. Le runtime (Runtime) se compile automatiquement en code local. L'efficacité d'exécution et la qualité du code sont grandement améliorées et le type de données est garanti. . Sécurité.
Utilisation de génériques C#
Ce qui suit consiste à utiliser des génériques pour réécrire la pile ci-dessus, en utilisant un type de données commun T comme espace réservé, en attendant qu'une valeur réelle soit utilisée lors du type d'instanciation à la place. Jetons un coup d'œil à la puissance des génériques :
public class Stack { (int i) { this.m_item = new T[i]; La méthode d'écriture de la classe reste la même. type de données T et il peut être appliqué à n’importe quel type de données et est de type sécurisé. Méthode d'appel de cette classe :
// L'instanciation ne peut enregistrer que les classes de type int Stack a = new Stack(100); Type de données int x = a.Pop(); // L'instanciation ne peut enregistrer que les classes de type chaîne Stack b = new Stack(100); b.Push(10); // Cette ligne ne se compile pas car la classe b reçoit uniquement des données de type chaîne b.Push("8888"); string y = b.Pop(); objet :
1. Il est de type sécurisé. Si une pile de type int est instanciée, les données de type string ne peuvent pas être traitées, et il en va de même pour les autres types de données.
2. Pas besoin d'emballer et de plier les boîtes. Lorsque cette classe est instanciée, le code local est généré en fonction du type de données transmis. Le type de données du code local a été déterminé, il n'est donc pas nécessaire de boxer et de plier.
3. Aucune conversion de type requise.
Connaissances théoriques :
Les soi-disant génériques : utiliser des types paramétrés pour faire fonctionner plusieurs types de données sur le même code. La programmation générique est un paradigme de programmation qui utilise des « types paramétrés » pour abstraire les types afin d'obtenir une réutilisation plus flexible.
Les génériques C# confèrent au code une sécurité de type plus forte, une meilleure réutilisation, une efficacité plus élevée et des contraintes plus claires.
Les capacités génériques C# sont prises en charge par le CLR au moment de l'exécution, ce qui est différent du mécanisme de modèle de compilation de C et de la « méthode d'effacement » de Java au moment de la compilation. Cela permet aux fonctionnalités génériques d'interagir de manière transparente entre les langages compatibles CLR.
Lorsque le code générique C# est compilé en IL et en métadonnées, des espaces réservés spéciaux sont utilisés pour représenter les types génériques et des instructions IL propriétaires sont utilisées pour prendre en charge les opérations génériques. Le véritable travail d'instanciation générique s'effectue « à la demande » lors de la compilation JIT.
Le mécanisme de compilation générique C# est le suivant :
Lors du premier tour de compilation, le compilateur génère uniquement le code IL "version générique" et les métadonnées pour le type Stack, et n'effectue pas de compilation générique. types d'instanciation, T agit uniquement comme un espace réservé au milieu.
Lors de la compilation JIT, lorsque le compilateur JIT rencontre Stack pour la première fois, il remplacera T -- dans la "version générique" du code IL et des métadonnées par le type int pour instancier le type générique.
CLR génère le même code pour tous les types génériques dont les paramètres de type sont des "types de référence", mais si le paramètre de type est un "type de valeur", le CLR le générera pour chaque "type de valeur" différent. Un distinct code.
Plusieurs fonctionnalités des génériques C#
Si les paramètres du type générique instancié sont les mêmes, le compilateur JIT réutilisera le type, de sorte que la capacité générique dynamique de C# évite que les modèles statiques C puissent provoquer une surcharge de code .
Les types génériques C# contiennent des métadonnées riches, de sorte que les types génériques C# peuvent être appliqués à une puissante technologie de réflexion.
Les génériques de C# utilisent la méthode de contrainte de « classe de base, interface, constructeur, type valeur/type de référence » pour implémenter des « contraintes explicites » sur les paramètres de type, ce qui améliore la sécurité du type mais perd également la grande flexibilité des modèles C basés sur sur les contraintes implicites des « signatures ».
Lorsqu'une classe générique C# est compilée, le code intermédiaire IL est d'abord généré, et le type général T n'est qu'un espace réservé. Lors de l'instanciation d'une classe, T est remplacé par le type de données spécifié par l'utilisateur et le code local est généré par le compilateur juste à temps (JIT). Le type de données réel a été utilisé dans ce code local, ce qui est équivalent à. la classe écrite avec le type réel, donc elle est différente. Le code natif d'une classe fermée est différent. Selon ce principe, nous pouvons voir les choses de cette façon : différentes classes fermées de classes génériques sont des types de données différents.
De cette façon, les génériques sont non seulement plus flexibles, mais amènent également la simplicité et la simplicité du code à un nouveau niveau ! Plus besoin d’écrire du code spécifique pour différentes méthodes surchargées !
Les génériques C# sont un atout inestimable dans l’arsenal des outils de développement. Ils améliorent les performances, la sécurité des types et la qualité, réduisent les tâches de programmation répétitives et simplifient le modèle de programmation global, le tout grâce à une syntaxe élégante et lisible. Bien que les racines des génériques C# soient des modèles C, C# fait passer les génériques à un niveau supérieur en offrant sécurité et prise en charge au moment de la compilation. C# tire parti de la compilation en deux phases, des métadonnées et de concepts innovants tels que les contraintes et les méthodes générales. Il ne fait aucun doute que les futures versions de C# continueront à faire évoluer les génériques afin d’ajouter de nouvelles fonctionnalités et d’étendre les génériques à d’autres domaines du .NET Framework tels que l’accès aux données ou la localisation
C’est tout ce qui concerne l’utilisation de C#. génériques, veuillez faire attention au site Web PHP chinois (m.sbmmt.com) pour plus de contenu connexe !