En C #, le paramètre «T» est souvent utilisé pour définir des fonctions qui acceptent tout type de type. Ils sont utilisés pour écrire des classes et des méthodes génériques qui peuvent fonctionner avec n'importe quel type de données, tout en maintenant une sécurité de type stricte. Nous allons discuter de leur fonctionnement et de leur utilisation.
Comment ça marche Travail?
La variable "T" que vous avez probablement vue dans certaines définitions de méthodes s'appelle un Paramètre de type générique, ou simplement un "Générique". Les méthodes génériques qui utilisent T peuvent être utilisées avec n'importe quel type, ce qui facilite la définition de classes et de méthodes qui ne se soucient pas des données qu'elles gèrent mais qui souhaitent les conserver.
Par exemple, les collections utilisent des génériques, afin de pouvoir gérer tout ce que l'utilisateur leur lance. Il n’existe pas de définition différente pour liste
et liste
; à la place, il existe une définition pour liste
.
En pratique, cela ressemble à ce qui suit. Même s'il s'agit d'une classe et non d'une méthode, vous pouvez toujours lui transmettre des paramètres de type à l'aide du
syntaxe entre crochets. Ensuite, partout où vous avez besoin de référencer quelque chose de ce type, vous remplacez simplement le paramètre.
<img class = "imgchk9 alignnone wp-image-6502 size-full" data-pagespeed-lazy-src = "https://www.cloudsavvyit.com/thumbcache/0/0/89b7d18d52555603f9d1a2fcea786f2c/p/uploads/2020/08 /9ef85b7c.png "alt =" Passez les paramètres de type en utilisant
Mettre quoi que ce soit dans le <>
les crochets vous permettent d'utiliser ce nom à la place d'un type valide, n'importe où dans la définition de la classe ou de la méthode qui utilise ce paramètre. Si vous imaginez un GenericList
, partout où vous écrivez int
comme type que vous écririez à la place T
, et laissez à l'utilisateur le soin d'indiquer à cette classe le type à utiliser.
C’est vraiment aussi simple que cela. Pour un GenericList
, le code ci-dessus est fonctionnellement équivalent à l'écriture de ce qui suit, mais il convient de noter que cette définition n'inclut pas GenericList
, car tout ce qui est entre crochets est des paramètres de type et les primitives ne peuvent pas être utilisées comme noms de type. Pour une classe qui n'utilise aucun paramètre, comme celui-ci, elle est définie comme d'habitude sans crochets.
Vous pouvez en fait nommer cette variable T comme n'importe quoi, bien qu'il soit courant de la commencer au moins par "T." Si vous avez une fonction qui nécessite des arguments de type multiple, vous pouvez les nommer différemment, comme «TOutput» ou «TInput». Ceci est beaucoup utilisé dans les définitions de délégué et dans les dictionnaires où vous avez TKey et TValue.
Bien sûr, vous pouvez également utiliser des génériques dans les méthodes, ainsi que dans les interfaces et les délégués. Ils fonctionnent de la même manière et vous pouvez même passer le paramètre de type en tant que paramètre de type à une autre fonction.
Cependant, vous pouvez notamment utiliser le paramètre type dans les paramètres réels de la fonction. Vous devrez toujours le mettre <>
crochets, sinon ce sera juste un type invalide, mais vous pouvez utiliser le paramètre n'importe où dans la définition de cette méthode.
Ils sont particulièrement utiles dans les délégués, car vous pouvez les utiliser pour accepter des fonctions avec des paramètres variables.
Contraintes de type
Les génériques sont excellents, mais cela peut causer des problèmes lorsque la fonction est autorisée à prendre n'importe quel type que vous lui lancez. Parfois, il est préférable de mettre quelques restrictions d'utilisation.
Ceci est fait avec le où T:
syntaxe. La forme la plus simple de ceci est où T: ClassName
, qui garantit que le paramètre T doit être ou dériver du type donné Nom du cours
. Cela active le polymorphisme de type sécurisé, comme cette fonction qui prend n'importe quel type de Fruit et renvoie un liste
, Plutôt qu'un liste
, ce qui serait techniquement correct mais perdrait des informations de type précieuses.
Vous pouvez voir que si nous essayons d’utiliser cette fonction avec tout ce qui n’est pas un Fruit, le compilateur vous hurlera dessus.
Au-delà du simple héritage, il existe quelques contraintes plus utiles:
où T: InterfaceName
– commeT: nom de classe
mais s'assure que l'argument type implémente l'interface donnée.où T: classe
– garantit que l'argument de type est un type de référence.où T: struct
– garantit que l'argument type est un type valeur non Nullable.où T: notnull
– l'argument de type doit être de type non Nullable.où T: nouveau ()
– l'argument type doit pouvoir être construit sans paramètres.où T: TOther
– l'argument typeT
doit être ou dériver de l'argument typeTOther
.
Vous pouvez spécifier plusieurs contraintes dans une liste séparée par des virgules.