Ler em inglês

Partilhar via


Genéricos em .NET

Os genéricos permitem adaptar um método, classe, estrutura ou interface ao tipo de dados preciso em que atua. Por exemplo, em vez de utilizar a Hashtable classe, que permite que as teclas e valores sejam de qualquer tipo, pode utilizar 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 aumento da reutilização do código e a segurança do tipo.

Definição e utilização de genéricos

Os 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 utilizam. Uma classe de recolha genérica pode usar um parâmetro de tipo como espaço reservado para o tipo de objetos que armazena; os parâmetros do tipo aparecem como os tipos dos seus campos e os tipos de parâmetros dos seus métodos. Um método genérico pode usar o seu parâmetro de tipo como o tipo do seu valor de retorno ou como o tipo de um dos seus parâmetros formais. O seguinte código ilustra uma definição de classe genérica simples.

generic<typename T>
public ref class Generics
{
public:
    T Field;
};
public class Generic<T>
{
    public T Field;
}
Public Class Generic(Of T)
    Public Field As T

End Class

Quando cria uma instância de uma classe genérica, especifica os tipos reais para substituir os parâmetros do tipo. Isto estabelece uma nova classe genérica, referida como uma classe genérica construída, com os seus tipos escolhidos substituídos em todos os lugares que os parâmetros do tipo aparecem. O resultado é uma classe tipo seguro que é adaptada à sua escolha de tipos, como ilustra o seguinte código.

static void Main()
{
    Generics<String^>^ g = gcnew Generics<String^>();
    g->Field = "A string";
    //...
    Console::WriteLine("Generics.Field           = \"{0}\"", g->Field);
    Console::WriteLine("Generics.Field.GetType() = {0}", g->Field->GetType()->FullName);
}
public static void Main()
{
    Generic<string> g = new Generic<string>();
    g.Field = "A string";
    //...
    Console.WriteLine("Generic.Field           = \"{0}\"", g.Field);
    Console.WriteLine("Generic.Field.GetType() = {0}", g.Field.GetType().FullName);
}
Public Shared Sub Main()
    Dim g As New Generic(Of String)
    g.Field = "A string"
    '...
    Console.WriteLine("Generic.Field           = ""{0}""", g.Field)
    Console.WriteLine("Generic.Field.GetType() = {0}", g.Field.GetType().FullName)
End Sub

Terminologia genérica

Os seguintes termos são usados para discutir genéricos em .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 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, não é possível criar instâncias de uma classe, estrutura ou interface que seja uma definição de tipo genérico.

  • Os parâmetros genéricos do tipo, ou parâmetros do tipo, são os espaços reservados numa definição genérica de tipo ou método. O System.Collections.Generic.Dictionary<TKey,TValue> tipo genérico tem dois parâmetros tipo, TKey e TValue, que representam os tipos das suas teclas e valores.

  • Um tipo genérico construído, ou tipo construído, é o resultado de tipos de especificação para os parâmetros genéricos de uma definição de tipo genérico.

  • Um argumento genérico é qualquer tipo que é substituído por um parâmetro genérico do tipo.

  • O termo geral genérico inclui tanto os tipos construídos como as definições genéricas.

  • A covariância e a contravariância dos parâmetros genéricos permitem-lhe utilizar tipos genéricos construídos cujos argumentos de tipo são mais derivados (covariância) ou menos derivados (contravariância) do que um tipo de alvo construído. A covariância e a contravariância são colectivamente referidas como variação. Para mais informações, consulte Covariance e Contravariance.

  • Os constrangimentos são limites colocados nos parâmetros genéricos do tipo. Por exemplo, pode limitar um parâmetro de tipo aos tipos que implementam a System.Collections.Generic.IComparer<T> interface genérica, para garantir que as instâncias do tipo possam ser encomendadas. Também pode restringir os parâmetros do tipo a tipos que têm uma determinada classe base, que têm um construtor sem parâmetros, ou que são tipos de referência ou tipos de valor. Os utilizadores do tipo genérico não podem substituir argumentos de tipo que não satisfaçam os constrangimentos.

  • Uma definição de método genérico é um método com duas listas de parâmetros: uma lista de parâmetros genéricos do tipo e uma lista de parâmetros formais. Os parâmetros do tipo podem aparecer como o tipo de devolução ou como os tipos dos parâmetros formais, como mostra o seguinte código.

generic<typename T>
T Generic(T arg)
{
    T temp = arg;
    //...
    return temp;
}
T Generic<T>(T arg)
{
    T temp = arg;
    //...
    return temp;
}
Function Generic(Of T)(ByVal arg As T) As T
    Dim temp As T = arg
    '...
    Return temp
End Function

Os métodos genéricos podem aparecer em tipos genéricos ou não-genéricos. É importante notar 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 de cobertura. Um método só é genérico se tiver a sua própria lista de parâmetros de tipo. No seguinte código, apenas o método G é genérico.

ref class A
{
    generic<typename T>
    T G(T arg)
    {
        T temp = arg;
        //...
        return temp;
    }
};
generic<typename T>
ref class Generic
{
    T M(T arg)
    {
        T temp = arg;
        //...
        return temp;
    }
};
class A
{
    T G<T>(T arg)
    {
        T temp = arg;
        //...
        return temp;
    }
}
class Generic<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 Generic(Of T)
    Function M(ByVal arg As T) As T
        Dim temp As T = arg
        '...
        Return temp
    End Function
End Class

Vantagens e desvantagens dos genéricos

Existem muitas vantagens em usar coleções genéricas e delegados:

  • Tipo de segurança. Os genéricos transferem o fardo da segurança do tipo de ti para o compilador. Não é necessário escrever código para testar o tipo de dados correto porque é aplicado no momento da compilação. A necessidade de fundição de tipo e a possibilidade de erros de tempo de execução são reduzidas.

  • Menos código e código é mais facilmente reutilizado. Não há necessidade de herdar de um tipo de base e de substituir membros. Por exemplo, o LinkedList<T> está pronto para uso imediato. Por exemplo, pode criar uma lista de cordas ligada com a seguinte declaração variável:

    LinkedList<String^>^ llist = gcnew LinkedList<String^>();
    
    LinkedList<string> llist = new LinkedList<string>();
    
    Dim llist As New LinkedList(Of String)()
    
  • Melhor desempenho. Os tipos de recolha genérica geralmente têm um melhor desempenho para armazenar e manipular tipos de valor porque não há necessidade de encaixotá-lo.

  • Os delegados genéricos permitem chamadas de tipo seguro sem a necessidade de criar várias classes de delegados. Por exemplo, o Predicate<T> delegado genérico permite-lhe criar um método que implemente os seus próprios critérios de pesquisa para um determinado tipo e utilizar o seu método com métodos do Array tipo como Find, FindLaste FindAll.

  • Os genéricos dinamizam o código gerado dinamicamente. Quando utiliza genéricos com código gerado dinamicamente, não é necessário gerar o tipo. Isto aumenta o número de cenários em que pode utilizar métodos dinâmicos leves em vez de gerar conjuntos inteiros. Para obter mais informações, consulte Como: Definir e Executar Métodos Dinâmicos e DynamicMethod.

Seguem-se algumas limitações dos genéricos:

  • Os tipos genéricos podem ser derivados da maioria das classes base, tais como MarshalByRefObject (e os constrangimentos podem ser usados para exigir que os parâmetros genéricos do tipo derivam de classes base como MarshalByRefObject). No entanto, .NET não suporta tipos genéricos ligados ao contexto. Um tipo genérico pode ser derivado de ContextBoundObject, mas tentar criar um exemplo desse tipo causa um TypeLoadException.

  • As enumerações não podem ter parâmetros genéricos. Uma enumeração só pode ser genérica por acaso (por exemplo, porque está aninhada num tipo genérico que é definido usando Visual Basic, C#ou C++). Para obter mais informações, consulte "Enumerações" no Sistema tipo Comum.

  • Métodos dinâmicos leves não podem ser genéricos.

  • Em Visual Basic, C#e C++, um tipo aninhado que esteja fechado num tipo genérico não pode ser instantâneo a menos que os tipos tenham sido atribuídos aos parâmetros de tipo de todos os tipos de enclosing. Outra forma de dizer isto é que, em reflexão, um tipo aninhado que é definido usando estas línguas inclui os parâmetros de tipo de todos os seus tipos de envolvente. Isto permite que os parâmetros de tipo de tipos de enclosing sejam utilizados nas definições de membro de um tipo aninhado. Para obter mais informações, consulte "Nested Types" em MakeGenericType.

    Nota

    Um tipo aninhado que seja definido por emitir código num conjunto dinâmico ou através da utilização do Ilasm.exe (MONTAGEM IL) não é obrigado a incluir os parâmetros de tipo dos seus tipos de cobertura; no entanto, se não os incluir, os parâmetros do tipo não estão no âmbito da classe aninhada.

    Para obter mais informações, consulte "Nested Types" em MakeGenericType.

Biblioteca de classes e suporte linguístico

.NET fornece uma série de classes genéricas de recolha nos seguintes espaços de nome:

As interfaces genéricas para a implementação de comparações de tipo e igualdade são fornecidas no espaço de System nomes, juntamente com tipos genéricos de delegados para manipuladores de eventos, conversões e predicados de pesquisa.

O apoio aos genéricos foi adicionado ao System.Reflection espaço de nomes para examinar tipos genéricos e métodos genéricos, para System.Reflection.Emit emitir conjuntos dinâmicos que contenham tipos e métodos genéricos, e para System.CodeDom gerar gráficos de origem que incluam genéricos.

O tempo de execução da linguagem comum fornece novos opcodes e prefixos para suportar tipos genéricos em linguagem intermédia da Microsoft (MSIL), incluindo Stelem, LdelemUnbox_Any, , e ConstrainedReadonly.

Visual C++, C#e Visual Basic todos fornecem suporte total para definir e usar genéricos. Para obter mais informações sobre suporte linguístico, consulte Os Tipos Genéricos em Visual Basic, Introdução aos Genéricos e Visão Geral dos Genéricos em C++.

Tipos e Genéricos Aninhados

Um tipo que esteja aninhado num tipo genérico pode depender dos parâmetros do tipo de tipo de enclosão. O tempo de execução da linguagem comum considera que os tipos aninhados são genéricos, mesmo que não tenham parâmetros genéricos do tipo próprio. Quando criar uma instância de um tipo aninhado, deve especificar os argumentos do tipo para todos os tipos genéricos que encerram.

Título Descrição
Coleções Genéricas em .NET Descreve classes genéricas de recolha e outros tipos genéricos em .NET.
Delegados Genéricos para Manipular 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.
Interfaces Genéricas Descreve interfaces genéricas que fornecem funcionalidade comum entre famílias de tipos genéricos.
Covariance e Contravariance Descreve a covariância e a contravariância nos parâmetros genéricos do tipo.
Tipos de recolha comumente usados Fornece informações sumárias sobre as características e cenários de utilização dos tipos de recolha em .NET, incluindo tipos genéricos.
Quando usar coleções genéricas Descreve regras gerais para determinar quando se deve utilizar tipos de recolha genéricas.
Como: Definir um tipo genérico com emitem de reflexão Explica como gerar conjuntos dinâmicos que incluem tipos e métodos genéricos.
Tipos Genéricos em Visual Basic Descreve a funcionalidade genérica para utilizadores Visual Basic, incluindo tópicos de como usar e definir tipos genéricos.
Introdução aos Genéricos Fornece uma visão geral da definição e utilização de tipos genéricos para utilizadores C#.
Visão geral dos Genéricos em C++ Visual Descreve a funcionalidade genérica para utilizadores C++, incluindo as diferenças entre genéricos e modelos.

Referência

System.Collections.Generic

System.Collections.ObjectModel

System.Reflection.Emit.OpCodes