Einschränkungen für generische Typparameter (C++/CLI)

In generischen Typ- oder Methodendeklarationen können Sie einen Typparameter mit Einschränkungen qualifizieren. Eine Einschränkung ist eine Anforderung, die Typen erfüllen müssen, die als Typargumente verwendet werden. Eine Einschränkung könnte beispielsweise sein, dass das Typargument eine bestimmte Schnittstelle implementieren oder von einer bestimmten Klasse erben muss.

Einschränkungen sind optional; die Angabe einer Einschränkung für einen Parameter entspricht der Verwendung einer Object Einschränkung.

Syntax

where type-parameter : constraint-list

Parameter

type-parameter
Einer der Typparameterbezeichner, die eingeschränkt werden sollen.

constraint-list
Eine durch Trennzeichen getrennte Liste von Einschränkungsspezifikationen. Die Liste kann Schnittstellen enthalten, die von der type-parameter.

Die Liste kann auch eine Klasse enthalten. Um eine Basisklasseneinschränkung zu erfüllen, muss das Typargument dieselbe Klasse wie die Einschränkung sein oder von der Einschränkung abgeleitet werden. Geben Sie ref class an, dass das Typargument ein Bezugstyp sein muss, einschließlich eines classbeliebigen , interface, delegate, oder array Typs. Geben Sie value class an, dass das Typargument ein Werttyp sein muss. Jeder Werttyp außer Nullable<T> kann angegeben werden.

Sie können auch angeben gcnew() , dass das Typargument über einen öffentlichen parameterlosen Konstruktor verfügen muss.

Sie können auch einen generischen Parameter als Einschränkung angeben. Das typargument, das für den typ, den Sie einschränken, muss vom Typ der Einschränkung abgeleitet sein oder abgeleitet werden. Dieser Parameter wird als reinen Typeinschränkung bezeichnet.

Hinweise

Die Einschränkungsklausel besteht aus where einem Typparameter, einem Doppelpunkt (:) und der Einschränkung, die die Art der Einschränkung für den Typparameter angibt. where ist ein kontextbezogenes Schlüsselwort. Weitere Informationen finden Sie unter Kontextabhängige Schlüsselwörter. Trennen Sie mehrere where Klauseln durch ein Leerzeichen.

Einschränkungen werden auf Typparameter angewendet, um die Typen zu begrenzen, die als Argumente für einen generischen Typ oder eine generische Methode verwendet werden können.

Klassen- und Schnittstelleneinschränkungen geben an, dass die Argumenttypen zu einer bestimmten Klasse gehören, von einer bestimmten Klasse erben oder eine bestimmte Schnittstelle implementieren müssen.

Durch Anwendung von Einschränkungen auf generische Typen oder Methoden kann der Code in diesem Typ bzw. dieser Methode von den bekannten Features der eingeschränkten Typen profitieren. So können Sie beispielsweise eine generische Klasse erstellen, deren Typparameter die Schnittstelle IComparable<T> implementiert:

// generics_constraints_1.cpp
// compile with: /c /clr
using namespace System;
generic <typename T>
where T : IComparable<T>
ref class List {};

Diese Einschränkung erfordert, dass ein für T verwendetes Typargument IComparable<T> zur Kompilierzeit implementiert. Sie ermöglicht auch den Aufruf von Schnittstellenmethoden wie z.B. CompareTo. Für die Instanz des Typparameters ist keine Umwandlung notwendig, um Schnittstellenmethoden aufrufen zu können.

Statische Methoden in der Klasse des Typarguments können nicht über den Typparameter aufgerufen werden. sie können nur über den tatsächlichen benannten Typ aufgerufen werden.

Eine Einschränkung kann kein Werttyp sein, einschließlich integrierter Typen wie int z. B. oder double. Da Werttypen keine abgeleiteten Klassen haben können, konnte nur eine Klasse die Einschränkung erfüllen. In diesem Fall kann der generische Code umgeschrieben werden, und der Typparameter wird durch den angegebenen Werttyp ersetzt.

Einschränkungen sind in einigen Fällen erforderlich, da der Compiler die Verwendung von Methoden oder anderen Features eines unbekannten Typs nicht zulässt, es sei denn, die Einschränkungen deuten darauf hin, dass der unbekannte Typ die Methoden oder Schnittstellen unterstützt.

Mehrere Einschränkungen für den gleichen Typparameter können in einer durch Trennzeichen getrennten Liste angegeben werden.

// 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 {};

Bei mehreren Typparametern verwenden Sie für jeden eine where-Klausel. Zum Beispiel:

// 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 {};

Verwenden Sie Einschränkungen in Ihrem Code gemäß den folgenden Regeln:

  • Wenn mehrere Einschränkungen aufgeführt werden, kann dies in beliebiger Reihenfolge erfolgen.

  • Einschränkungen können auch Klassentypen sein, wie z.B. abstrakte Basisklasse. Einschränkungen können jedoch keine Werttypen oder sealed Klassen sein.

  • Einschränkungen können nicht selbst Typparameter sein, aber sie können die Typparameter in einen offenen konstruierten Typ einbeziehen. Zum Beispiel:

    // 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{};
    

Beispiele

Das folgende Beispiel veranschaulicht die Verwendung von Einschränkungen zum Aufrufen von Instanzmethoden in Typparametern.

// 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");
}
"parent" is not a senior
"grandfather" is a senior

Wenn ein generischer Typparameter als Einschränkung verwendet wird, wird er als nackte Typeinschränkung bezeichnet. Reine Typeinschränkungen sind nützlich, wenn eine Memberfunktion mit eigenem Typparameter diesen Parameter auf den Typparameter des enthaltenden Typs einschränken muss.

Im folgenden Beispiel ist T eine reine Typeinschränkung im Kontext der Add-Methode.

Reine Typeinschränkungen können auch in generischen Klassendefinitionen verwendet werden. Das Verwenden reiner Typeinschränkungen bei generischen Klassen ist nur bis zu einem gewissen Punkt nützlich, da der Compiler zu einer reinen Typeinschränkung nichts annehmen kann, außer dass sie von Object abgeleitet ist. Verwenden Sie reine Typeinschränkungen in generischen Klassen in Szenarien, wenn Sie eine Vererbungsbeziehung zwischen zwei Typparametern erzwingen möchten.

// 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 {};

Siehe auch

Generics