Compartilhar via


Tipos genéricos no Visual Basic (Visual Basic)

Um tipo genérico é um único elemento de programação que se adapta para executar a mesma funcionalidade para vários tipos de dados. Ao definir uma classe ou procedimento genérico, você não precisa definir uma versão separada para cada tipo de dados para o qual talvez você queira executar essa funcionalidade.

Uma analogia é um conjunto de chaves de fenda com cabeças removíveis. Você inspeciona o parafuso e seleciona a cabeça correta para ele (fenda, fenda cruzada, estrela). Depois de inserir a cabeça correta na alça da chave de fenda, você executará exatamente a mesma função com a chave de fenda, ou seja, girando o parafuso.

Diagrama de um conjunto de chaves de fenda com cabeças diferentes.

Quando você define um tipo genérico, parametriza-o com um ou mais tipos de dados. Os parâmetros de tipo permitem que o código adapte os tipos de dados aos seus requisitos. Seu código pode declarar vários elementos de programação diferentes do elemento genérico, cada um agindo em um conjunto diferente de tipos de dados. Mas todos os elementos declarados executam a lógica idêntica, independentemente dos tipos de dados que estão usando.

Por exemplo, talvez você queira criar e usar uma classe de fila que opera em um tipo de dados específico, como String. Você pode declarar essa classe de System.Collections.Generic.Queue<T>, como mostra o exemplo a seguir.

Public stringQ As New System.Collections.Generic.Queue(Of String)

Agora você pode usar stringQ para trabalhar exclusivamente com valores String. Como stringQ é específico para String em vez de ser generalizado para valores Object, você não tem associação tardia ou conversão de tipo. Tipos genéricos economizam tempo de execução e reduzem erros em tempo de execução.

Para obter mais informações sobre como usar um tipo genérico, consulte Como usar uma classe genérica.

Exemplo de uma classe genérica

O exemplo a seguir mostra a estrutura básica de uma classe genérica.

Public Class classHolder(Of t)
    Public Sub processNewItem(ByVal newItem As t)
        Dim tempItem As t
        ' Insert code that processes an item of data type t.
    End Sub
End Class

No esqueleto anterior, t é um parâmetro de tipo , ou seja, um espaço reservado para um tipo de dados que você fornece quando declara a classe. Em outro lugar do código, você pode declarar várias versões de classHolder fornecendo vários tipos de dados para t. O exemplo a seguir mostra duas dessas declarações.

Public integerClass As New classHolder(Of Integer)
Friend stringClass As New classHolder(Of String)

As instruções acima declaram classes construídas, nas quais um tipo específico substitui o parâmetro de tipo. Essa substituição é propagada em todo o código dentro da classe construída. O exemplo a seguir mostra a aparência do procedimento processNewItem no integerClass.

Public Sub processNewItem(ByVal newItem As Integer)
    Dim tempItem As Integer
    ' Inserted code now processes an Integer item.
End Sub

Para obter um exemplo mais completo, consulte Como definir uma classe que pode fornecer funcionalidade idêntica em diferentes tipos de dados.

Elementos de programação qualificados

Você pode definir e usar classes genéricas, estruturas, interfaces, procedimentos e delegados. O .NET define várias classes, estruturas e interfaces genéricas que representam elementos genéricos comumente usados. O namespace System.Collections.Generic fornece dicionários, listas, filas e pilhas. Antes de definir seu próprio elemento genérico, veja se ele já está disponível no System.Collections.Generic.

Os procedimentos não são tipos, mas você pode definir e usar procedimentos genéricos. Consulte Procedimentos genéricos no Visual Basic.

Vantagens dos tipos genéricos

Um tipo genérico serve como base para declarar vários elementos de programação diferentes, cada um deles opera em um tipo de dados específico. As alternativas a um tipo genérico são:

  1. Um único tipo que opera no tipo de dados Object.
  2. Um conjunto de versões específicas de tipos do tipo. Cada versão é codificada individualmente e opera em um tipo de dados específico, como String, Integerou um tipo definido pelo usuário, como customer.

Um tipo genérico tem as seguintes vantagens em relação a essas alternativas:

  • Segurança de tipos. Tipos genéricos impõem a verificação de tipo durante o tempo de compilação. Tipos baseados em Object aceitam qualquer tipo de dados e você deve escrever código para verificar se um tipo de dados de entrada é aceitável. Com tipos genéricos, o compilador pode detectar incompatibilidades de tipo antes do tempo de execução.
  • Desempenho. Tipos genéricos não precisam realizar a operação de box e unbox dos dados, pois cada um deles é especializado em um tipo de dado. As operações baseadas em Object devem realizar a operação de box dos tipos de dados de entrada para convertê-los em Object e realizar a operação de unbox dos dados destinados à saída. O boxe e o unboxing reduzem o desempenho. Os tipos com base em Object também são associados tardiamente, o que significa que o acesso a seus membros requer código extra no tempo de execução. Conversões de tipo também reduzem o desempenho.
  • Consolidação de código. O código em um tipo genérico deve ser definido apenas uma vez. Um conjunto de versões específicas de um tipo deve replicar o mesmo código em cada versão, com a única diferença sendo o tipo de dado específico para aquela versão. Com tipos genéricos, as versões específicas do tipo são todas geradas do tipo genérico original.
  • Reutilização de código. O código que não depende de um tipo de dados específico pode ser reutilizado com vários tipos de dados se for genérico. Muitas vezes, você pode reutilizá-lo mesmo com um tipo de dados que você não previu originalmente.
  • Suporte ao IDE. Quando você usa um tipo construído declarado de um tipo genérico, o IDE (ambiente de desenvolvimento integrado) pode dar mais suporte enquanto você está desenvolvendo seu código. Por exemplo, o IntelliSense pode mostrar as opções específicas de tipo de um argumento para um construtor ou método.
  • Algoritmos genéricos. Algoritmos abstratos que são independentes de tipo são bons candidatos para tipos genéricos. Por exemplo, um procedimento genérico que classifica itens usando a interface IComparable pode ser usado com qualquer tipo de dados que implemente IComparable.

Restrições

Embora o código em uma definição de tipo genérico deva ser o mais independente de tipo possível, talvez seja necessário exigir uma determinada funcionalidade de qualquer tipo de dados fornecido ao seu tipo genérico. Por exemplo, se você quiser comparar dois itens para classificar ou agrupar, o tipo de dados deve implementar a interface IComparable. Você pode impor esse requisito adicionando uma restrição ao parâmetro de tipo.

Exemplo de uma restrição

O exemplo a seguir mostra uma definição de esqueleto de uma classe com uma restrição que exige que o argumento de tipo implemente IComparable.

Public Class itemManager(Of t As IComparable)
    ' Insert code that defines class members.
End Class

Se o código subsequente tentar construir uma classe de itemManager fornecendo um tipo que não implementa IComparable, o compilador sinalizará um erro.

Tipos de restrições

Sua restrição pode especificar os seguintes requisitos em qualquer combinação:

  • O argumento de tipo deve implementar uma ou mais interfaces
  • O argumento de tipo deve ser do tipo ou herdar de, no máximo, uma classe
  • O argumento de tipo deve expor um construtor sem parâmetros acessível ao código que cria objetos a partir dele
  • O argumento de tipo deve ser um tipo de referência ou deve ser um tipo de valor

O código C# pode declarar que um argumento de tipo deve ser um tipo não gerenciado. O Visual Basic impõe essa restrição para o código do Visual Basic que usa um tipo ou método genérico que foi definido com essa restrição (em C#). No entanto, você não pode declarar uma restrição de unmanaged em um parâmetro de tipo no Visual Basic.

Se você precisar impor mais de um requisito, use uma lista de restrições separada por vírgulas dentro de chaves ({ }). Para exigir um construtor acessível, inclua a palavra-chave Novo operador na lista. Para exigir um tipo de referência, inclua a palavra-chave Class; para exigir um tipo de valor, você inclui a palavra-chave Structure.

Para obter mais informações sobre restrições, consulte Type List.

Exemplo de várias restrições

O exemplo a seguir mostra uma definição de esqueleto de uma classe genérica com uma lista de restrições no parâmetro de tipo. No código que cria uma instância dessa classe, o argumento de tipo deve implementar as interfaces IComparable e IDisposable, ser um tipo de referência e expor um construtor sem parâmetros acessível.

Public Class thisClass(Of t As {IComparable, IDisposable, Class, New})
    ' Insert code that defines class members.
End Class

Termos importantes

Os tipos genéricos introduzem e utilizam os seguintes termos:

  • Tipo genérico. Uma definição de uma classe, estrutura, interface, procedimento ou delegado para a qual você fornece pelo menos um tipo de dados ao declará-la.
  • Tipo de Parâmetro. Em uma definição de tipo genérico, um espaço reservado para um tipo de dados fornecido ao declarar o tipo.
  • Argumento de tipo. Um tipo de dados específico que substitui um parâmetro de tipo quando você declara um tipo construído de um tipo genérico.
  • Restrição. Uma condição em um parâmetro de tipo que restringe o argumento de tipo que você pode fornecer para ele. Uma restrição pode exigir que o argumento de tipo implemente uma interface específica, herda de uma classe específica, tenha um construtor sem parâmetros acessível ou seja um tipo de referência ou um tipo de valor. Você pode combinar essas restrições, mas pode especificar no máximo uma classe base.
  • Tipo construído. Uma classe, estrutura, interface, procedimento ou delegado declarado de um tipo genérico fornecendo argumentos de tipo para os parâmetros de tipo.

Consulte também