Partilhar via


Tipos genéricos no Visual Basic (Visual Basic)

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

Uma analogia é um conjunto de chave de fenda com cabeças removíveis. Você inspeciona o parafuso e seleciona a cabeça correta para esse parafuso (ranhurado, cruzado, estrelado). Depois de inserir a cabeça correta na alça da chave de fenda, você executa exatamente a mesma função com a chave de fenda, ou seja, girar o parafuso.

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

Ao definir um tipo genérico, você o parametriza com um ou mais tipos de dados. Os parâmetros de tipo permitem que o código adapte os tipos de dados às suas necessidades. Seu código pode declarar vários elementos de programação diferentes do elemento genérico, cada um atuando 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 opere em um tipo de dados específico, como String. Você pode declarar essa classe a partir de System.Collections.Generic.Queue<T>, como mostra o exemplo a seguir.

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

Agora pode usar stringQ para trabalhar com valores String exclusivamente. Como stringQ é específico para String em vez de ser generalizado para valores Object, você não tem vinculação tardia ou conversão de tipo. Os tipos genéricos economizam tempo de execução e reduzem os erros de 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 seguinte mostra uma definição de estrutura 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 outra parte do seu código, você pode declarar várias versões do 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 anteriores declaram as classes construídas , nas quais um tipo específico substitui o parâmetro de tipo. Essa substituição é propagada por 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 elegíveis

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, verifique 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 de base para declarar vários elementos de programação diferentes, cada um dos quais opera em um tipo de dados específico. As alternativas a um tipo genérico são:

  1. Um único tipo operando no tipo de dados Object.
  2. Um conjunto de versões específicas 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 sobre estas alternativas:

  • Segurança do tipo. Os tipos genéricos impõem a verificação de tipo em tempo de compilação. Os 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 detetar incompatibilidades de tipo antes do tempo de execução.
  • Desempenho. Os tipos genéricos não precisam caixa e descaixa dados, porque cada um é especializado para um tipo de dados. As operações baseadas em Object devem encaixotar tipos de dados de entrada para convertê-los em Object e descompactar dados destinados à saída. Boxe e unboxing reduzem o desempenho. Os tipos baseados em Object também são tardios, o que significa que o acesso aos seus membros requer código extra em tempo de execução. As conversões de tipo também reduzem o desempenho.
  • Consolidação de código. O código num tipo genérico tem de 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 a ser o tipo de dados específico para essa versão. Com tipos genéricos, as versões específicas do tipo são todas geradas a partir 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 IDE. Quando você usa um tipo construído declarado a partir de um tipo genérico, o ambiente de desenvolvimento integrado (IDE) pode fornecer mais suporte enquanto você está desenvolvendo seu código. Por exemplo, o IntelliSense pode mostrar as opções específicas do tipo para um argumento para um construtor ou método.
  • Algoritmos Genéricos. Algoritmos abstratos que são independentes do 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érica deva ser o mais independente de tipo possível, talvez seja necessário exigir um determinado recurso de qualquer tipo de dados fornecido ao seu tipo genérico. Por exemplo, se você quiser comparar dois itens para classificar ou agrupar, seu tipo de dados deve implementar a interface IComparable. Você pode impor esse requisito adicionando uma restrição de ao parâmetro type.

Exemplo de uma restrição

O exemplo a seguir mostra uma definição de esqueleto de uma classe com uma restrição que requer o argumento type para implementar 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 a partir de itemManager fornecendo um tipo que não implementa IComparable, o compilador sinaliza um erro.

Tipos de restrições

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

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

O código C# pode declarar que um argumento type deve ser um tipo não gerenciado. Visual Basic impõe essa restrição para o código do Visual Basic que usa um tipo genérico ou método 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 de separada por vírgulas chaves internas ({ }). Para exigir um construtor acessível, inclua a palavra-chave New Operator na lista. Para exigir um tipo de referência, inclua a palavra-chave Class; Para exigir um tipo de valor, inclua a palavra-chave Structure.

Para obter mais informações sobre restrições, consulte Lista de tipos.

Exemplo de restrições múltiplas

O exemplo a seguir mostra uma definição de esqueleto de uma classe genérica com uma lista de restrições no parâmetro type. No código que cria uma instância dessa classe, o argumento type 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 o qual você fornece pelo menos um tipo de dados ao declará-lo.
  • Parâmetro Tipo. Em uma definição de tipo genérica, um espaço reservado para um tipo de dados que você fornece quando declara o tipo.
  • Tipo de Argumento. Um tipo de dados específico que substitui um parâmetro de tipo quando se declara um tipo construído de um tipo genérico.
  • Restrição. Uma condição em um parâmetro type que restringe o argumento type que você pode fornecer para ele. Uma restrição pode exigir que o argumento type implemente uma interface específica, herde 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 a partir de um tipo genérico fornecendo argumentos de tipo para os seus parâmetros de tipo.

Ver também