Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Os genéricos permitem que você adapte um método, uma classe, uma estrutura ou uma interface para o tipo de dados preciso em que ele atua. Por exemplo, em vez de usar a Hashtable classe, que permite que chaves e valores sejam de qualquer tipo, você pode usar a Dictionary<TKey,TValue> classe genérica e especificar os tipos permitidos para a chave e o valor. Entre os benefícios dos genéricos estão o aumento da reutilização de código e a segurança do tipo.
Definir e usar genéricos
Genéricos são classes, estruturas, interfaces e métodos que têm espaços reservados (parâmetros de tipo) para um ou mais dos tipos que armazenam ou usam. Uma classe de coleção genérica pode usar um parâmetro de tipo como um espaço reservado para o tipo de objetos que armazena. Os parâmetros de tipo aparecem como os tipos de seus campos e os tipos de parâmetro de seus métodos. Um método genérico pode usar seu parâmetro de tipo como o tipo de seu valor retornado ou como o tipo de um de seus parâmetros formais.
O código a seguir ilustra uma definição de classe genérica simples.
public class SimpleGenericClass<T>
{
public T Field;
}
Public Class SimpleGenericClass(Of T)
Public Field As T
End Class
Ao criar uma instância de uma classe genérica, você especifica os tipos reais para substituir os parâmetros de tipo. Isso estabelece uma nova classe genérica, conhecida como uma classe genérica construída, com os tipos escolhidos substituídos em todos os lugares em que os parâmetros de tipo aparecem. O resultado é uma classe com segurança de tipos que é adaptada à sua escolha de tipos, como ilustra o código a seguir.
public static void Main()
{
SimpleGenericClass<string> g = new SimpleGenericClass<string>();
g.Field = "A string";
//...
Console.WriteLine($"SimpleGenericClass.Field = \"{g.Field}\"");
Console.WriteLine($"SimpleGenericClass.Field.GetType() = {g.Field.GetType().FullName}");
}
Public Shared Sub Main()
Dim g As New SimpleGenericClass(Of String)
g.Field = "A string"
'...
Console.WriteLine("SimpleGenericClass.Field = ""{0}""", g.Field)
Console.WriteLine("SimpleGenericClass.Field.GetType() = {0}", g.Field.GetType().FullName)
End Sub
Terminologia
Os seguintes termos são usados para discutir genéricos no .NET:
Uma definição de tipo genérico é uma declaração de classe, estrutura ou interface que funciona como um modelo, com espaços reservados para os tipos que ele pode conter ou usar. Por exemplo, a System.Collections.Generic.Dictionary<TKey,TValue> classe pode conter dois tipos: chaves e valores. Como uma definição de tipo genérico é apenas um modelo, você não pode criar instâncias de uma classe, estrutura ou interface que seja uma definição de tipo genérico.
Parâmetros de tipo genérico, ou parâmetros de tipo, são os espaços reservados em uma definição de tipo ou método genérico. O System.Collections.Generic.Dictionary<TKey,TValue> tipo genérico tem dois parâmetros de tipo,
TKeyeTValue, que representam os tipos de suas chaves e valores.Um tipo genérico construído, ou tipo construído, é o resultado da especificação de tipos para os parâmetros de tipo genérico de uma definição de tipo genérico.
Um argumento de tipo genérico é qualquer tipo que é substituído por um parâmetro de tipo genérico.
O tipo genérico de termo geral inclui tipos construídos e definições de tipo genérico.
A covariância e a contravariância de parâmetros de tipo genérico permitem que você use tipos genéricos construídos cujos argumentos de tipo são mais derivados (covariância) ou menos derivados (contravariância) do que um tipo construído de destino. Covariância e contravariância são coletivamente conhecidas como variação. Para obter mais informações, consulte Covariância e contravariância.
Restrições são limites colocados em parâmetros de tipo genérico. Por exemplo, você pode limitar um parâmetro de tipo a tipos que implementam a System.Collections.Generic.IComparer<T> interface genérica, para garantir que instâncias do tipo possam ser ordenadas. Você também pode restringir parâmetros de tipo a tipos que têm uma classe base específica, que têm um construtor sem parâmetros ou que são tipos de referência ou tipos de valor. Os usuários do tipo genérico não podem substituir argumentos de tipo que não atendem às restrições.
Uma definição de método genérico é um método com duas listas de parâmetros: uma lista de parâmetros de tipo genérico e uma lista de parâmetros formais. Os parâmetros de tipo podem aparecer como o tipo de retorno ou como os tipos dos parâmetros formais, como mostra o código a seguir.
T MyGenericMethod<T>(T arg) { T temp = arg; //... return temp; }Function MyGenericMethod(Of T)(ByVal arg As T) As T Dim temp As T = arg '... Return temp End FunctionMétodos genéricos podem aparecer em tipos genéricos ou não genéricos. É importante observar que um método não é genérico apenas porque pertence a um tipo genérico ou mesmo porque tem parâmetros formais cujos tipos são os parâmetros genéricos do tipo delimitante. Um método só será genérico se tiver sua própria lista de parâmetros de tipo. No código a seguir, somente o método
Gé genérico.class A { T G<T>(T arg) { T temp = arg; //... return temp; } } class MyGenericClass<T> { T M(T arg) { T temp = arg; //... return temp; } }Class A Function G(Of T)(ByVal arg As T) As T Dim temp As T = arg '... Return temp End Function End Class Class MyGenericClass(Of T) Function M(ByVal arg As T) As T Dim temp As T = arg '... Return temp End Function End Class
Vantagens e desvantagens de genéricos
Há muitas vantagens em usar coleções e delegados genéricos:
Segurança do tipo Os genéricos deslocam a responsabilidade pela segurança de tipos de você para o compilador. Não é necessário escrever código para testar o tipo de dados correto porque ele é imposto no momento da compilação. A necessidade de conversão de tipo e a possibilidade de erros de tempo de execução são reduzidas.
Menos código e o código é reutilizado com mais facilidade. Não é necessário herdar de um tipo base e substituir membros. Por exemplo, o LinkedList<T> está pronto para uso imediato. Por exemplo, você pode criar uma lista vinculada de cadeias de caracteres com a seguinte declaração de variável:
LinkedList<string> llist = new LinkedList<string>();Dim llist As New LinkedList(Of String)()Melhor desempenho. Os tipos de coleção genéricos geralmente têm melhor desempenho para armazenar e manipular tipos de valor, porque não há necessidade de realizar o boxing dos tipos de valor.
Os delegados genéricos habilitam retornos de chamada com tipagem segura sem a necessidade de criar várias classes de delegados. Por exemplo, o Predicate<T> delegado genérico permite que você crie um método que implemente seus próprios critérios de pesquisa para um tipo específico e use seu método com métodos do Array tipo, como Find, FindLaste FindAll.
Os genéricos simplificam o código gerado dinamicamente. Quando você usa genéricos com código gerado dinamicamente, não é necessário gerar o tipo. Isso aumenta o número de cenários em que você pode usar métodos dinâmicos leves em vez de gerar assemblies inteiros. Para obter mais informações, consulte Como definir e executar métodos dinâmicos e DynamicMethod.
Veja a seguir algumas limitações de genéricos:
Tipos genéricos podem ser derivados da maioria das classes base, como MarshalByRefObject (e restrições podem ser usadas para exigir que parâmetros de tipo genérico derivam de classes base como MarshalByRefObject). No entanto, o .NET não dá suporte a tipos genéricos associados ao contexto. Um tipo genérico pode ser derivado de ContextBoundObject, mas tentar criar uma instância desse tipo causa um TypeLoadException.
As enumerações não podem ter parâmetros de tipo genéricos. Uma enumeração pode ser genérica apenas por acaso (por exemplo, porque está aninhada em um tipo genérico definido usando Visual Basic, C#ou C++). Para obter mais informações, consulte "Enumerações" no Common Type System.
Métodos dinâmicos leves não podem ser genéricos.
No Visual Basic, C#, e C++, um tipo aninhado que está dentro de um tipo genérico não pode ser instanciado, a menos que os tipos tenham sido atribuídos aos parâmetros de tipo de todos os tipos que cercam. Outra maneira de dizer isso é que, em reflexão, um tipo aninhado definido usando essas linguagens inclui os parâmetros de tipo de todos os seus tipos delimitantes. Isso permite que os parâmetros de tipo dos tipos envolventes sejam usados nas definições de membro de um tipo aninhado. Para obter mais informações, consulte "Tipos Aninhados" em MakeGenericType.
Observação
Um tipo aninhado definido pela emissão de código em um assembly dinâmico ou usando o Ilasm.exe (IL Assembler) não é obrigado a incluir os parâmetros de tipo de seus tipos envolventes; no entanto, se ele não os incluir, os parâmetros de tipo não estarão no escopo na classe aninhada.
Para obter mais informações, consulte "Tipos Aninhados" em MakeGenericType.
Suporte à biblioteca de classes e ao idioma
O .NET fornece várias classes de coleção genéricas nos seguintes namespaces:
O System.Collections.Generic namespace contém a maioria dos tipos de coleção genéricos fornecidos pelo .NET, como as List<T> classes e Dictionary<TKey,TValue> genéricas.
O System.Collections.ObjectModel namespace contém tipos de coleção genéricos adicionais, como a ReadOnlyCollection<T> classe genérica, que são úteis para expor modelos de objeto aos usuários de suas classes.
Interfaces genéricas para implementar comparações de classificação e igualdade são fornecidas no System namespace, juntamente com tipos delegados genéricos para manipuladores de eventos, conversões e predicados de pesquisa.
O System.Numerics namespace fornece interfaces genéricas para funcionalidade matemática (disponível no .NET 7 e versões posteriores). Para obter mais informações, consulte matemática genérica.
O suporte para genéricos foi adicionado ao namespace System.Reflection para examinar tipos e métodos genéricos, ao System.Reflection.Emit para emitir assemblies dinâmicos que contêm tipos e métodos genéricos, e ao System.CodeDom para gerar grafos de origem que incluem genéricos.
O common language runtime fornece novos opcodes e prefixos para dar suporte a tipos genéricos em CIL (common intermediate language), incluindo Stelem, Ldelem, Unbox_Any, Constrained e Readonly.
Visual C++, C#e Visual Basic oferecem suporte completo para definir e usar genéricos. Para obter mais informações sobre o suporte a idiomas, consulte Tipos Genéricos no Visual Basic, Introdução a Genéricos e Visão Geral de Genéricos no Visual C++.
Tipos aninhados e genéricos
Um tipo aninhado em um tipo genérico pode depender dos parâmetros de tipo do tipo genérico delimitante. O common language runtime considera os tipos aninhados genéricos, mesmo que eles não tenham parâmetros de tipo genéricos próprios. Ao criar uma instância de um tipo aninhado, você deve especificar argumentos de tipo para todos os tipos genéricos delimitados.
Artigos relacionados
| Título | Descrição |
|---|---|
| Coleções genéricas no .NET | Descreve classes de coleção genéricas e outros tipos genéricos no .NET. |
| Delegados genéricos para manipulação de matrizes e listas | Descreve delegados genéricos para conversões, predicados de pesquisa e ações a serem tomadas em elementos de uma matriz ou coleção. |
| Matemática genérica | Descreve como você pode executar operações matemáticas genericamente. |
| Interfaces genéricas | Descreve interfaces genéricas que fornecem funcionalidade comum entre famílias de tipos genéricos. |
| Covariância e contravariância | Descreve a covariância e a contravariância em parâmetros de tipo genérico. |
| Tipos de coleção comumente usados | Fornece informações resumidas sobre as características e os cenários de uso dos tipos de coleção no .NET, incluindo tipos genéricos. |
| Quando usar coleções genéricas | Descreve regras gerais para determinar quando usar tipos de coleção genéricos. |
| Como definir um tipo genérico com a emissão de reflexão | Explica como criar assemblies dinâmicos que incluem tipos e métodos genéricos. |
| Tipos genéricos no Visual Basic | Descreve o recurso genérico para usuários do Visual Basic, incluindo tópicos de instruções para usar e definir tipos genéricos. |
| Introdução aos genéricos | Fornece uma visão geral da definição e do uso de tipos genéricos para usuários C#. |
| Visão geral de genéricos no Visual C++ | Descreve o recurso genérico para usuários do C++, incluindo as diferenças entre genéricos e modelos. |