Compartir a través de


Restricciones de parámetros de tipo genérico (C++/CLI)

En declaraciones genéricas de tipo o método, puede calificar un parámetro de tipo con restricciones. Una restricción es un requisito que los tipos se usaban como argumentos de tipo debe satisfacer. Por ejemplo, una restricción podría ser que el argumento de tipo debe implementar alguna interfaz o heredar de una clase concreta.

Las restricciones son opcionales; no especificar una restricción en un parámetro equivale a restringir ese parámetro a Object.

where type-parameter: constraint list

Parámetros

  • parámetro de tipo
    Uno de los parámetros de tipo, ser restringidos.

  • lista de restricciones
    la lista de restricciones es una lista separada por comas de las especificaciones de la restricción. La lista puede contener las interfaces que se implementen por el parámetro de tipo.

    La lista también puede incluir una clase. Para que el argumento de tipo cumple una restricción de la clase base, debe ser la misma clase que la restricción o derivar de la restricción.

    También puede especificar gcnew() para indicar que el argumento de tipo debe tener un constructor sin parámetros público; o ref class para indicar el argumento de tipo debe ser un tipo de referencia, incluido cualquier clase, interfaz, delegado, o tipo de matriz; o value class para indicar el argumento de tipo debe ser un tipo de valor. Cualquier tipo de valor excepto Nullable<T>> puede ser especificado.

    También puede especificar un parámetro genérico como restricción. El argumento de tipo proporcionado para el tipo que está obligando debe ser o derivar del tipo de restricción. Esto se denomina una restricción de tipo naked.

Comentarios

La cláusula de restricción consta de where seguido de un parámetro de tipo, dos puntos (:), y la restricción, que especifica la naturaleza de la restricción en el parámetro de tipo. where es una palabra clave contextual; vea Palabras clave contextuales (Extensiones de componentes de C++) para obtener más información. Varias cláusulas independientes de where por un espacio.

Las restricciones se aplican para escribir parámetros para colocar limitaciones en los tipos que se pueden utilizar como argumentos para un tipo o método genérico.

Restricciones de clase y de interfaz especifican que los tipos de argumentos deben ser o heredar de una clase especificada o implementar una interfaz especificada.

La aplicación de restricciones a un tipo o método genérico permite que el código de ese tipo o método se aprovecha de las características conocidas de tipos restringidos. Por ejemplo, puede declarar una clase genérica de tal manera que el parámetro de tipo implementa la interfaz de IComparable<T> :

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

Esta restricción requiere que escribir el argumento utilizado para T implemente IComparable<T> en tiempo de compilación. También permite que los métodos de interfaz, como CompareTo, son denominados. No es necesaria ninguna conversión en una instancia del parámetro de tipo a los métodos de interfaz.

Los métodos estáticos en la clase del argumento de tipo no pueden llamar a con el parámetro de tipo; pueden llamar sólo mediante el tipo denominado real.

Una restricción no puede ser un tipo de valor, incluidos tipos integrados como int o double. Puesto que los tipos de valor no pueden tener clases derivadas, solo una clase podría no cumplir la restricción. En ese caso, el genérico se puede volver a escribir con el parámetro de tipo reemplazado por el tipo de valor específico.

Las restricciones se requieren en algunos casos porque el compilador no permitirá el uso de métodos u otras características de un desconocido escriben a menos que las restricciones implican que el tipo desconocido admite los métodos o interfaces.

Los varias restricciones para el mismo parámetro de tipo se pueden especificar en una lista separada por comas

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

Con parámetros de tipo múltiples, utilice una cláusula de where para cada parámetro de tipo. Por ejemplo:

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

En resumen, utilizar restricciones en el código según las reglas siguientes:

  • Si se enumeran los varias restricciones, las restricciones se pueden mostrar en cualquier orden.

  • Restricciones también pueden ser tipos de clase, como clases base abstractas. Sin embargo, las restricciones no pueden ser tipos de valor o clases selladas.

  • Las restricciones no pueden propios ser parámetros de tipo, pero pueden implicar los parámetros de tipo en un tipo construido abierto. Por ejemplo:

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

Ejemplo

El ejemplo siguiente se muestra con restricciones a los métodos de instancia de parámetros de tipo.

// 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");
}
  

Cuando un parámetro de tipo genérico se usa como restricción, se llama a una restricción de tipo naked. Las restricciones de tipo naked son útiles cuando una función miembro con su propio parámetro de tipo debe restringir qué parámetro al parámetro de tipo del tipo contenedor.

En el ejemplo siguiente, t es una restricción de tipo naked en el contexto del método add.

Las restricciones de tipo naked también se pueden utilizar en definiciones de clases genéricas. La utilidad de las restricciones de tipo naked con clases genéricas se limita porque el compilador no puede suponer nada sobre una restricción de tipo naked salvo que deriva de Object. El naked de uso escribe restricciones en clases genéricas en escenarios en los que desea aplicar una relación de herencia entre dos parámetros de tipo.

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

Vea también

Otros recursos

Genéricos (Extensiones de componentes de C++)