Compartilhar via


Tipos anônimos (Visual Basic)

O Visual Basic dá suporte a tipos anônimos, que permitem criar objetos sem escrever uma definição de classe para o tipo de dados. Em vez disso, o compilador gera uma classe para você. A classe não tem nenhum nome utilizável, herda diretamente de Object e contém as propriedades especificadas ao declarar o objeto. Como o nome do tipo de dados não é especificado, ele é conhecido como um tipo anônimo.

O exemplo a seguir declara e cria variável product como uma instância de um tipo anônimo que tem duas propriedades Name e Price.

' Variable product is an instance of a simple anonymous type.
Dim product = New With {Key .Name = "paperclips", .Price = 1.29}

Uma expressão de consulta usa tipos anônimos para combinar colunas de dados selecionadas por uma consulta. Você não pode definir o tipo do resultado com antecedência, pois não é possível prever as colunas que uma consulta específica pode selecionar. Tipos anônimos permitem que você escreva uma consulta que selecione qualquer número de colunas, em qualquer ordem. O compilador cria um tipo de dados que corresponde às propriedades especificadas e à ordem especificada.

Nos exemplos a seguir, products há uma lista de objetos de produto, cada um deles com muitas propriedades. A variável namePriceQuery contém a definição de uma consulta que, quando executada, retorna uma coleção de instâncias de um tipo anônimo que tem duas propriedades Name e Price.

Dim namePriceQuery = From prod In products
                     Select prod.Name, prod.Price

A variável nameQuantityQuery contém a definição de uma consulta que, quando executada, retorna uma coleção de instâncias de um tipo anônimo que tem duas propriedades Name e OnHand.

Dim nameQuantityQuery = From prod In products
                        Select prod.Name, prod.OnHand

Para obter mais informações sobre o código criado pelo compilador para um tipo anônimo, consulte a Definição de Tipo Anônimo.

Cuidado

O nome do tipo anônimo é gerado pelo compilador e pode variar de compilação para compilação. Seu código não deve usar ou depender do nome de um tipo anônimo porque o nome pode mudar quando um projeto é recompilado.

Declarar um tipo anônimo

A declaração de uma instância de um tipo anônimo usa uma lista de inicializadores para especificar as propriedades do tipo. Você só pode especificar propriedades quando declara um tipo anônimo, não outros elementos de classe, como métodos ou eventos. No exemplo a seguir, product1 é uma instância de um tipo anônimo que tem duas propriedades: Name e Price.

' Variable product1 is an instance of a simple anonymous type.
Dim product1 = New With {.Name = "paperclips", .Price = 1.29}
' -or-
' product2 is an instance of an anonymous type with key properties.
Dim product2 = New With {Key .Name = "paperclips", Key .Price = 1.29}

Se você designar propriedades como propriedades de chave, poderá usá-las para comparar duas instâncias de tipo anônimo quanto à igualdade. No entanto, os valores das propriedades de chave não podem ser alterados. Consulte a seção Propriedades da Chave mais adiante neste tópico para obter mais informações.

Observe que declarar uma instância de um tipo anônimo é como declarar uma instância de um tipo nomeado usando um inicializador de objeto:

' Variable product3 is an instance of a class named Product.
Dim product3 = New Product With {.Name = "paperclips", .Price = 1.29}

Para obter mais informações sobre outras maneiras de especificar propriedades de tipo anônimo, consulte Como inferir nomes e tipos de propriedade em declarações de tipo anônimo.

Propriedades Principais

As propriedades principais diferem das propriedades não chave de várias maneiras fundamentais:

  • Somente os valores das propriedades de chave são comparados para determinar se duas instâncias são iguais.

  • Os valores das propriedades chave são somente leitura e não podem ser alterados.

  • Somente os valores das propriedades principais são incluídos no algoritmo de código hash gerado pelo compilador para um tipo anônimo.

Igualdade

Instâncias de tipos anônimos só poderão ser iguais se forem instâncias do mesmo tipo anônimo. O compilador tratará duas instâncias como instâncias do mesmo tipo se atenderem às seguintes condições:

  • Elas são declaradas no mesmo assembly.

  • Suas propriedades têm os mesmos nomes, os mesmos tipos inferidos e são declaradas na mesma ordem. As comparações de nomes não diferenciam maiúsculas de minúsculas.

  • As mesmas propriedades em cada uma delas são marcadas como propriedades de chave.

  • Pelo menos uma propriedade em cada declaração é uma propriedade de chave.

Uma instância de um tipo anônimo que não tem propriedades de chave é igual apenas a si mesma.

' prod1 and prod2 have no key values.
Dim prod1 = New With {.Name = "paperclips", .Price = 1.29}
Dim prod2 = New With {.Name = "paperclips", .Price = 1.29}

' The following line displays False, because prod1 and prod2 have no
' key properties.
Console.WriteLine(prod1.Equals(prod2))

' The following statement displays True because prod1 is equal to itself.
Console.WriteLine(prod1.Equals(prod1))

Duas instâncias do mesmo tipo anônimo serão iguais se os valores de suas propriedades de chave forem iguais. Os exemplos a seguir ilustram como a igualdade é testada.

Dim prod3 = New With {Key .Name = "paperclips", Key .Price = 1.29}
Dim prod4 = New With {Key .Name = "paperclips", Key .Price = 1.29}
' The following line displays True, because prod3 and prod4 are
' instances of the same anonymous type, and the values of their
' key properties are equal.
Console.WriteLine(prod3.Equals(prod4))

Dim prod5 = New With {Key .Name = "paperclips", Key .Price = 1.29}
Dim prod6 = New With {Key .Name = "paperclips", Key .Price = 1.29,
                      .OnHand = 423}
' The following line displays False, because prod5 and prod6 do not 
' have the same properties.
Console.WriteLine(prod5.Equals(prod6))

Dim prod7 = New With {Key .Name = "paperclips", Key .Price = 1.29,
                      .OnHand = 24}
Dim prod8 = New With {Key .Name = "paperclips", Key .Price = 1.29,
                      .OnHand = 423}
' The following line displays True, because prod7 and prod8 are
' instances of the same anonymous type, and the values of their
' key properties are equal. The equality check does not compare the
' values of the non-key field.
Console.WriteLine(prod7.Equals(prod8))

Valores somente leitura

Os valores das propriedades de chave não podem ser alterados. Por exemplo, no prod8 do exemplo anterior, os campos Name e Price são read-only, mas OnHand pode ser alterado.

' The following statement will not compile, because Name is a key
' property and its value cannot be changed.
' prod8.Name = "clamps"

' OnHand is not a Key property. Its value can be changed.
prod8.OnHand = 22

Tipos anônimos de expressões de consulta

As expressões de consulta nem sempre exigem a criação de tipos anônimos. Quando possível, elas usam um tipo existente para manter os dados da coluna. Isso ocorre quando a consulta retorna registros inteiros da fonte de dados ou apenas um campo de cada registro. Nos exemplos de código a seguir, customers é uma coleção de objetos de uma classe Customer. A classe tem muitas propriedades e você pode incluir uma ou mais delas no resultado da consulta, em qualquer ordem. Nos dois primeiros exemplos, nenhum tipo anônimo é necessário porque as consultas selecionam elementos de tipos nomeados:

  • custs1 contém uma coleção de cadeias de caracteres, porque cust.Name é uma cadeia de caracteres.

    Dim custs1 = From cust In customers
                 Select cust.Name
    
  • custs2 contém uma coleção de Customer objetos, pois cada elemento customers é um Customer objeto e todo o elemento é selecionado pela consulta.

    Dim custs2 = From cust In customers
                 Select cust
    

No entanto, nem sempre estão disponíveis os tipos nomeados apropriados. Talvez você queira selecionar nomes e endereços de clientes para uma finalidade, números de ID do cliente e locais para outro e nomes de clientes, endereços e históricos de pedidos para um terceiro. Tipos anônimos permitem que você selecione qualquer combinação de propriedades, em qualquer ordem, sem primeiro declarar um novo tipo nomeado para manter o resultado. Em vez disso, o compilador cria um tipo anônimo para cada compilação de propriedades. A consulta a seguir seleciona apenas o nome do cliente e o número de ID de cada Customer objeto em customers. Portanto, o compilador cria um tipo anônimo que contém apenas essas duas propriedades.

Dim custs3 = From cust In customers
             Select cust.Name, cust.ID

Os nomes e os tipos de dados das propriedades no tipo anônimo são retirados dos argumentos de Select, cust.Name e cust.ID. As propriedades em um tipo anônimo que é criado por uma consulta são sempre propriedades de chave. Quando custs3 é executado no loop For Each a seguir, o resultado é uma coleção de instâncias de um tipo anônimo com duas propriedades principais, Name e ID.

For Each selectedCust In custs3
    Console.WriteLine(selectedCust.ID & ": " & selectedCust.Name)
Next

Os elementos na coleção representada por custs3 tem tipos fortes e você pode usar o IntelliSense para navegar pelas propriedades disponíveis e verificar seus tipos.

Para obter mais informações, consulte Introdução ao LINQ no Visual Basic.

Decidir se deseja usar tipos anônimos

Antes de criar um objeto como uma instância de uma classe anônima, considere se essa é a melhor opção. Por exemplo, se você quiser criar um objeto temporário para conter dados relacionados e não precisar de outros campos e métodos que uma classe completa possa conter, um tipo anônimo será uma boa solução. Tipos anônimos também são convenientes se você quiser uma seleção diferente de propriedades para cada declaração ou se quiser alterar a ordem das propriedades. No entanto, se o projeto incluir vários objetos que têm as mesmas propriedades, em uma ordem fixa, você poderá declará-los com mais facilidade usando um tipo nomeado com um construtor de classe. Por exemplo, com um construtor apropriado, é mais fácil declarar várias instâncias de uma Product classe do que declarar várias instâncias de um tipo anônimo.

' Declaring instances of a named type.
Dim firstProd1 As New Product("paperclips", 1.29)
Dim secondProd1 As New Product("desklamp", 28.99)
Dim thirdProd1 As New Product("stapler", 5.09)

' Declaring instances of an anonymous type.
Dim firstProd2 = New With {Key .Name = "paperclips", Key .Price = 1.29}
Dim secondProd2 = New With {Key .Name = "desklamp", Key .Price = 28.99}
Dim thirdProd2 = New With {Key .Name = "stapler", Key .Price = 5.09}

Outra vantagem dos tipos nomeados é que o compilador pode capturar um erro de digitação acidental de um nome de propriedade. Nos exemplos anteriores, firstProd2, secondProd2e thirdProd2 se destinam a ser instâncias do mesmo tipo anônimo. No entanto, se você declarasse thirdProd2 acidentalmente de uma das seguintes maneiras, seu tipo seria diferente do de firstProd2 e secondProd2.

' Dim thirdProd2 = New With {Key .Name = "stapler", Key .Price = 5.09}
' Dim thirdProd2 = New With {Key .Name = "stapler", Key .Price = "5.09"}
' Dim thirdProd2 = New With {Key .Name = "stapler", .Price = 5.09}

Mais importante, há limitações sobre o uso de tipos anônimos que não se aplicam a instâncias de tipos nomeados. firstProd2, secondProd2e thirdProd2 são instâncias do mesmo tipo anônimo. No entanto, o nome do tipo anônimo compartilhado não está disponível e não pode aparecer onde um nome de tipo é esperado em seu código. Por exemplo, um tipo anônimo não pode ser usado para definir uma assinatura de método, para declarar outra variável ou campo ou em qualquer declaração de tipo. Como resultado, os tipos anônimos não são apropriados quando você precisa compartilhar informações entre métodos.

Uma definição de tipo anônimo

Em resposta à declaração de uma instância de um tipo anônimo, o compilador cria uma nova definição de classe que contém as propriedades especificadas.

Se o tipo anônimo contiver pelo menos uma propriedade de chave, a definição substituirá três membros herdados de Object: Equals, GetHashCodee ToString. O código produzido para testar a igualdade e determinar o valor do código hash considera apenas as propriedades de chave. Se o tipo anônimo não contiver propriedades de chave, somente ToString será substituído. Propriedades explicitamente nomeadas de um tipo anônimo não podem entrar em conflito com esses métodos gerados. Ou seja, você não pode usar .Equalsou .GetHashCode.ToString nomear uma propriedade.

Definições de tipo anônimo que têm pelo menos uma propriedade de chave também implementam a System.IEquatable<T> interface, onde T está o tipo do tipo anônimo.

Para obter mais informações sobre o código criado pelo compilador e a funcionalidade dos métodos substituídos, consulte Anonymous Type Definition.

Consulte também