Restrições em parâmetros de tipo genérico (C++/CLI)
Em instruções genéricas do tipo ou do método, você pode qualificar um parâmetro de tipo com restrições. Uma restrição é um requisito que tenha usado como argumentos de tipo devem satisfazer. Por exemplo, uma restrição pode ser que o argumento de tipo deve implementar uma determinada a interface ou herdar de uma classe específica.
As restrições são opcionais; não especifique uma restrição em um parâmetro é equivalente a restringir esse parâmetro a Object.
where type-parameter: constraint list
Parâmetros
parâmetro de tipo
Um dos parâmetros de tipo, para ser restringido.a lista de restrições
a lista de restrição é uma lista separada por vírgulas das especificações de restrição. A lista pode incluir as interfaces a serem implementadas pelo parâmetro de tipo.A lista também pode incluir uma classe. Para que o argumento de tipo de conteúdo uma restrição da classe base, deve ser a mesma classe que a restrição ou derivar de restrição.
Você também pode especificar gcnew() para indicar que o argumento de tipo deve ter um construtor público; sem parâmetros ou ref class para indicar o argumento de tipo deve ser um tipo de referência, incluindo qualquer classe, interface, ou tipo delegado de matriz; ou value class para indicar o argumento de tipo deve ser um tipo de valor. Qualquer tipo de valor exceto NullableT<> pode ser especificado.
Você também pode especificar um parâmetro genérico como uma restrição. O argumento de tipo fornecido para o tipo que você está restringindo deve ser ou derivar do tipo de restrição. Isso é chamado de uma restrição despida do tipo.
Comentários
A cláusula de restrição consiste em where seguido por um parâmetro de tipo, por dois-pontos (:), e pela restrição, que especifica a natureza de restrição no parâmetro de tipo. where é uma palavra-chave contextuais; consulte Palavras-chave Contextuais (Extensões de Componentes C++) para obter mais informações. Várias cláusulas de where separadas por um espaço.
As restrições são aplicadas aos parâmetros de tipo para colocar restrições em tipos que podem ser usados como argumentos para um tipo ou um método genérico.
As restrições da classe e da interface que especificam os tipos de argumento deve ser ou herdar de uma classe especificada ou implementar uma interface especificada.
A aplicação de restrições a um tipo genérico ou a um método permite que o código nesse tipo método ou beneficiar-se de recursos restritos conhecidos de tipos. Por exemplo, você pode declarar uma classe genérico de modo que implementa o parâmetro de tipo a interface de IComparable<T> :
// generics_constraints_1.cpp
// compile with: /c /clr
using namespace System;
generic <typename T>
where T : IComparable<T>
ref class List {};
Essa restrição requer que um argumento de tipo usado para T implementa IComparable<T> em tempo de compilação. Também permite que os métodos da interface, como CompareTo, sejam chamados. Nenhuma conversão é necessária em uma instância do tipo de parâmetro chamar métodos da interface.
Os métodos estáticos na classe do argumento de tipo não podem ser chamados com o parâmetro de tipo; só podem ser chamados por meio do tipo denominado real.
Uma restrição não pode ser um tipo de valor, incluindo tipos internos como int ou double. Como os tipos de valor não podem ter classes derivadas, somente uma classe pode nunca atender à restrição. Nesse caso, o genérico pode ser recriado com o parâmetro de tipo substituído pelo tipo de valor específico.
As restrições são necessárias em alguns casos já que o compilador não permitirá o uso dos métodos ou outros recursos de um tipo desconhecido a menos que as restrições implicarem que o tipo desconhecido da suporte aos métodos ou interfaces.
Várias restrições para o mesmo parâmetro de tipo podem ser especificadas em uma lista separada por vírgulas
// 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 {};
Com vários parâmetros do tipo, use uma cláusula de where para cada parâmetro de tipo. Por exemplo:
// 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 {};
Para resumir, para usar restrições em seu código de acordo com as seguintes regras:
Se várias restrições são listadas, as restrições podem ser listadas em qualquer ordem.
As restrições podem também ser do tipo de classe, como classes base abstratos. Porém, as restrições não podem ser do tipo de valor ou classes seladas.
As restrições não podem ser eles mesmos parâmetros de tipo, mas podem envolver os parâmetros de tipo em um tipo construído aberto. Por exemplo:
// 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{};
Exemplo
O exemplo a seguir demonstra o uso de restrições para chamar métodos de instância em 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");
}
Quando um parâmetro de tipo genérico é usado como uma restrição, ele será denominado uma restrição despida do tipo. As restrições despidas do tipo são úteis quando uma função de membro com seu próprio parâmetro de tipo precisa se restringir quais parâmetro ao parâmetro do tipo de contêiner.
No exemplo a seguir, T é uma restrição despida do tipo no contexto do método ser adicionado.
As restrições despidas do tipo também podem ser usadas em definições de classe genéricas. A utilidade de restrições despidas do tipo com classes genéricas é limitada porque o compilador não pode assumir nada sobre uma restrição despida do tipo exceto que se deriva de Object. Use restrições despidas de tipo em classes genéricas em cenários em que você deseja impor uma relação de herança entre dois 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 {};