Contraintes sur les paramètres de type générique (C++/CLI)
dans le type générique ou les déclarations de méthode, vous pouvez qualifier un paramètre de type avec des contraintes.une contrainte est une condition que les types ont utilisé comme les arguments de type doivent satisfaire.Par exemple, une contrainte peut indiquer que l'argument de type implémente une certaine interface ou hérite d'une classe spécifique.
les contraintes sont facultatives ; ne pas spécifier une contrainte pour un paramètre est équivalent à limiter ce paramètre à Object.
where type-parameter: constraint list
Paramètres
paramètre de type
Un des paramètres de type, être soumis.liste de contraintes
la liste de contraintes est une liste avec la virgule comme séparateur des caractéristiques de contrainte.La liste peut inclure des interfaces à implémenter par le paramètre de type.La liste peut également inclure une classe.pour que l'argument de type satisfasse une contrainte de classe de base, il doit être la même classe que la contrainte ou dériver de la contrainte.
Vous pouvez également spécifier gcnew() pour indiquer l'argument de type doit avoir un constructeur sans paramètre public ; ou ref class pour indiquer l'argument de type doit être un type référence, y compris toute classe, interface, délégué, ou type tableau ; ou value class pour indiquer l'argument de type doit être un type valeur.Tout type valeur sauf <T> nullable peut être spécifié.
vous pouvez également spécifier un paramètre générique comme contrainte.L'argument de type fourni pour le type que vous appliquez une contrainte doit être ou dériver du type de la contrainte.Il s'agit d'une contrainte de type naked de type.
Notes
La clause de contrainte se compose de where suivi d'un paramètre de type, de deux-points (Numéro de téléphone :), et la contrainte, qui spécifie la nature de la restriction au paramètre de type.where est un mot clé contextuel ; consultez Mots clés contextuels (extensions du composant C++) pour plus d'informations.Plusieurs clauses distinctes de where par un espace.
Les contraintes sont appliquées aux paramètres de type pour placer des restrictions sur les types qui peuvent être utilisés comme arguments pour un type ou une méthode générique.
La classe et les contraintes d'interface spécifiez les types d'argument doit être ou hériter d'une classe spécifiée ou implémenter une interface spécifiée.
L'application de contraintes à un type ou une méthode générique permet au code dans ce type ou méthode pour tirer parti des fonctionnalités des types contraints.Par exemple, vous pouvez déclarer une classe générique de sorte que le paramètre de type implémente l'interface d' IComparable <T> :
// generics_constraints_1.cpp
// compile with: /c /clr
using namespace System;
generic <typename T>
where T : IComparable<T>
ref class List {};
cette contrainte requiert qu'un argument de type utilisé pourT implémente IComparable<T> au moment de la compilation.Il permet également aux méthodes d'interface, telles que CompareTo, pour être appelé.Aucun cast n'est nécessaire sur une instance du paramètre de type pour appeler les méthodes d'interface.
Les méthodes statiques dans la classe de l'argument de type ne peuvent pas être appelées à travers le paramètre de type ; elles peuvent être appelées uniquement via le type nommé réel.
Une contrainte ne peut pas être un type valeur, notamment les types intégrés tels qu' int ou double.Les types valeur ne peuvent avoir de classes dérivées, une seule classe peut jamais répondre à la contrainte.dans ce cas, le générique peut être réécrit avec le paramètre de type remplacé par le type valeur spécifique.
Les contraintes sont requises dans certains cas comme le compilateur ne permet pas l'utilisation des méthodes ou d'autres fonctionnalités d'un type inconnu à moins que les contraintes impliquent que le type inconnu prend en charge les méthodes ou des interfaces.
Plusieurs contraintes pour le même paramètre de type peuvent être spécifiés dans une liste avec la virgule comme séparateur
// generics_constraints_2.cpp
// compile with: /c /clr
using namespace System;
using namespace System::Collections::Generic;
generic <typename T>
where T : List<T>, IComparable<T>
ref class List {};
Avec plusieurs paramètres de type, utilisez une clause de where pour chaque paramètre de type.Par exemple :
// generics_constraints_3.cpp
// compile with: /c /clr
using namespace System;
using namespace System::Collections::Generic;
generic <typename K, typename V>
where K: IComparable<K>
where V: IComparable<K>
ref class Dictionary {};
Pour résumer, utiliser des contraintes dans votre code en fonction de les règles suivantes :
Si plusieurs contraintes sont répertoriées, les contraintes peuvent apparaître dans n'importe quel ordre.
Les contraintes peuvent également être des types de classe, tels que les classes de base abstraite.Toutefois, les contraintes ne peuvent pas être des types valeur ou des classes sealed.
Les contraintes ne peuvent pas eux-mêmes être des paramètres de type, mais elles peuvent nécessiter les paramètres de type dans un type construit ouvert.Par exemple :
// generics_constraints_4.cpp // compile with: /c /clr generic <typename T> ref class G1 {}; generic <typename Type1, typename Type2> where Type1 : G1<Type2> // OK, G1 takes one type parameter ref class G2{};
Exemple
L'exemple suivant illustre l'utilisation des contraintes pour appeler des méthodes d'instance sur les paramètres de type.
// generics_constraints_5.cpp
// compile with: /clr
using namespace System;
interface class IAge {
int Age();
};
ref class MyClass {
public:
generic <class ItemType> where ItemType : IAge
bool isSenior(ItemType item) {
// Because of the constraint,
// the Age method can be called on ItemType.
if (item->Age() >= 65)
return true;
else
return false;
}
};
ref class Senior : IAge {
public:
virtual int Age() {
return 70;
}
};
ref class Adult: IAge {
public:
virtual int Age() {
return 30;
}
};
int main() {
MyClass^ ageGuess = gcnew MyClass();
Adult^ parent = gcnew Adult();
Senior^ grandfather = gcnew Senior();
if (ageGuess->isSenior<Adult^>(parent))
Console::WriteLine("\"parent\" is a senior");
else
Console::WriteLine("\"parent\" is not a senior");
if (ageGuess->isSenior<Senior^>(grandfather))
Console::WriteLine("\"grandfather\" is a senior");
else
Console::WriteLine("\"grandfather\" is not a senior");
}
Lorsqu'un paramètre de type générique est utilisé comme contrainte, il est appelé une contrainte de type naked de type.Les contraintes de type naked de type sont utiles lorsqu'une fonction membre avec son propre paramètre de type doit limiter ce paramètre au paramètre de type du type conteneur.
Dans l'exemple suivant, T est une contrainte de type naked de type dans le contexte de la méthode d'ajouter.
Les contraintes de type naked de type peuvent également être utilisées dans les définitions de classe génériques.L'utilité des contraintes de type naked de type avec les classes génériques est limitée car le compilateur peut n'en supposant que rien à propos d'une contrainte de type naked mais il dérive d' Object.Utilisez les contraintes de type naked de type sur les classes génériques dans les scénarios dans lesquels vous voulez appliquer une relation d'héritage entre deux paramètres de type.
// generics_constraints_6.cpp
// compile with: /clr /c
generic <class T>
ref struct List {
generic <class U>
where U : T
void Add(List<U> items) {}
};
generic <class A, class B, class C>
where A : C
ref struct SampleClass {};