Tipos anônimos

Os tipos anônimos fornecem um modo conveniente de encapsular um conjunto de propriedades somente leitura em um único objeto sem a necessidade de primeiro definir explicitamente um tipo. O nome do tipo é gerado pelo compilador e não está disponível no nível do código-fonte. O tipo de cada propriedade é inferido pelo compilador.

Crie tipos anônimos usando o operador new com um inicializador de objeto. Para obter mais informações sobre inicializadores de objeto, consulte Inicializadores de Objeto e Coleção.

O exemplo a seguir mostra um tipo anônimo que é inicializado com duas propriedades chamadas Amount e Message.

var v = new { Amount = 108, Message = "Hello" };

// Rest the mouse pointer over v.Amount and v.Message in the following
// statement to verify that their inferred types are int and string.
Console.WriteLine(v.Amount + v.Message);

Os tipos anônimos são normalmente usados na cláusula select de uma expressão de consulta para retornar um subconjunto das propriedades de cada objeto na sequência de origem. Para obter mais informações sobre consultas, consulte LINQ no C#.

Os tipos anônimos contêm uma ou mais propriedades públicas somente leitura. Nenhum outro tipo de membros da classe, como métodos ou eventos, é válido. A expressão que é usada para inicializar uma propriedade não pode ser null, uma função anônima ou um tipo de ponteiro.

O cenário mais comum é inicializar um tipo anônimo com propriedades de outro tipo. No exemplo a seguir, suponha que existe uma classe com o nome Product. A classe Product inclui as propriedades Color e Price, além de outras propriedades que não lhe interessam. A variável products é uma coleção de objetos do Product. A declaração do tipo anônimo começa com a palavra-chave new. A declaração inicializa um novo tipo que usa apenas duas propriedades de Product. O uso de tipos anônimos faz com que uma menor quantidade de dados seja retornada na consulta.

Quando você não especifica os nomes de membros no tipo anônimo, o compilador dá aos membros de tipo anônimo o mesmo nome da propriedade que está sendo usada para inicializá-los. Forneça um nome para a propriedade que está sendo inicializada com uma expressão, como mostrado no exemplo anterior. No exemplo a seguir, os nomes das propriedades do tipo anônimo são Color e Price .

var productQuery =
    from prod in products
    select new { prod.Color, prod.Price };

foreach (var v in productQuery)
{
    Console.WriteLine("Color={0}, Price={1}", v.Color, v.Price);
}

Dica

Você pode usar a regra de estilo .NET IDE0037 para impor se os nomes de membros inferidos ou explícitos são preferenciais.

Também é possível definir um campo por objeto de outro tipo: classe, struct ou até mesmo outro tipo anônimo. Isso é feito usando a variável que contém esse objeto exatamente como no exemplo a seguir, onde dois tipos anônimos são criados usando tipos definidos pelo usuário já instanciados. Em ambos os casos o campo product nos tipos anônimos shipment e shipmentWithBonus serão do tipo Product contendo seus valores padrão de cada campo. E o campo bonus será do tipo anônimo criado pelo compilador.

var product = new Product();
var bonus = new { note = "You won!" };
var shipment = new { address = "Nowhere St.", product };
var shipmentWithBonus = new { address = "Somewhere St.", product, bonus };

Normalmente, ao usar um tipo anônimo para inicializar uma variável, a variável é declarada como uma variável local de tipo implícito usando var. O nome do tipo não pode ser especificado na declaração da variável, porque apenas o compilador tem acesso ao nome subjacente do tipo anônimo. Para obter mais informações sobre var, consulte Variáveis de local digitadas implicitamente.

Você pode criar uma matriz de elementos de tipo anônimo combinando uma variável local de tipo implícito e uma matriz de tipo implícito, como mostrado no exemplo a seguir.

var anonArray = new[] { new { name = "apple", diam = 4 }, new { name = "grape", diam = 1 }};

Os tipos anônimos são tipos class que derivam diretamente de object e que não podem ser convertidos para qualquer tipo, exceto para object. O compilador fornece um nome para cada tipo anônimo, embora o seu aplicativo não possa acessá-lo. Do ponto de vista do Common Language Runtime, um tipo anônimo não é diferente de qualquer outro tipo de referência.

Se dois ou mais inicializadores de objeto anônimos em um assembly especificarem uma sequência de propriedades que estão na mesma ordem e que têm os mesmos nomes e tipos, o compilador tratará os objetos como instâncias do mesmo tipo. Eles compartilham o mesmo tipo de informação gerado pelo compilador.

Tipos anônimos dão suporte a mutações não destrutivas na forma de expressões with. Isso permite que você crie uma nova instância de um tipo anônimo em que uma ou mais propriedades têm novos valores:

var apple = new { Item = "apples", Price = 1.35 };
var onSale = apple with { Price = 0.79 };
Console.WriteLine(apple);
Console.WriteLine(onSale);

Você não pode declarar que um campo, uma propriedade, um evento ou um tipo de retorno de um método tem um tipo anônimo. Da mesma forma, não pode declarar que um parâmetro formal de um método, propriedade, construtor ou indexador tem um tipo anônimo. Para passar um tipo anônimo ou uma coleção que contenha tipos anônimos como um argumento para um método, você pode declarar o parâmetro como tipo object. No entanto, usar object para tipos anônimos anula o propósito da tipagem forte. Se você precisa armazenar os resultados da consulta ou passá-los fora do limite do método, considere o uso de uma estrutura ou classe com denominação comum em vez de um tipo anônimo.

Como os métodos Equals e GetHashCode em tipos anônimos são definidos em termos dos métodos das propriedades Equals e GetHashCode, duas instâncias do mesmo tipo anônimo são iguais somente se todas as suas propriedades forem iguais.

Observação

O nível de acessibilidade de um tipo anônimo é internal, portanto, dois tipos anônimos definidos em assemblies diferentes não são do mesmo tipo. Portanto, instâncias de tipos anônimos não podem ser iguais umas às outras quando definidas em assemblies diferentes, mesmo quando todas as suas propriedades são iguais.

Tipos anônimos substituem o método ToString, concatenando o nome e a saída ToString de cada propriedade cercada por chaves.

var v = new { Title = "Hello", Age = 24 };

Console.WriteLine(v.ToString()); // "{ Title = Hello, Age = 24 }"