Cast de tipos anônimos no Csharp

Veja neste artigo, de forma simples e clara, como trabalhar com conversões de tipos anônimos no C#. Os tipos anônimos facilitam a manipulação de objetos nos quais precisamos definir certas propriedades, sem precisar criar uma classe previamente.

Os tipos anônimos são uma “mão na roda” quando queremos criar objetos de uma classe (que não precisa ser criada previamente) com propriedades a partir do resultado de uma consulta em LINQ. O problema começa quando saímos do escopo dos objetos anônimos criados, por exemplo, quando atribuímos os mesmos em um tipo object e retornamos em um método.

Como o compilador gera o nome para a classe do objeto anônimo (algo parecido com isso: <>f__AnonymousType0`2) não é possível fazer o cast utilizando o mesmo, então qual a solução?

Para mostrar um exemplo do cenário descrito vamos utilizar uma aplicação que basicamente cria uma lista de pessoas, e como resultado de uma consulta retorna um objeto anônimo com alguns dados da pessoa solicitada. Vamos criar um aplicação ASP.NET Web Forms:

Primeiro criamos as classes abaixo:

namespace Modelo { public class Pessoa { public int id { get; set; } public string nome { get; set; } public DateTime dataNascimento { get; set; } public Telefone telefone { get; set; } public static IEnumerable<Pessoa> Carregar() { return new List<Pessoa>() { new Pessoa() { id = 1, nome = "João", dataNascimento = DateTime.Today.AddYears(-20), telefone = new Telefone() { id = 1, ddd = "43", numero = "11112222" }}, new Pessoa() { id = 2, nome = "Maria", dataNascimento = DateTime.Today.AddYears(-30), telefone = new Telefone() { id = 2, ddd = "44", numero = "22224444" }}, new Pessoa() { id = 3, nome = "Aline", dataNascimento = DateTime.Today.AddYears(-40), telefone = new Telefone() { id = 3, ddd = "45", numero = "33334444" }}, new Pessoa() { id = 4, nome = "José", dataNascimento = DateTime.Today.AddYears(-10), telefone = new Telefone() { id = 4, ddd = "46", numero = "55556666" }}, new Pessoa() { id = 5, nome = "Fernanda", dataNascimento = DateTime.Today.AddYears(-15), telefone = new Telefone() { id = 5, ddd = "47", numero = "77778888" }}, new Pessoa() { id = 6, nome = "Carlos", dataNascimento = DateTime.Today.AddYears(-30), telefone = new Telefone() { id = 6, ddd = "48", numero = "99999999" }} }; } public static object Pesquisar(int id) { var Pessoas = Carregar(); var resultado = (from p in Pessoas where p.id == id select new { DataNascimento = p.dataNascimento, Telefone = string.Format("() ", p.telefone.ddd,p.telefone.numero) }).Single(); return resultado; } } public class Telefone { public int id { get; set; } public string ddd { get; set; } public string numero { get; set; } } }
Listagem 1. Classes criadas no exemplo

Entendendo o código:

Criamos as classes Pessoa e Telefone. A classe Pessoa contém um método chamado Carregar que retorna uma lista com alguns objetos do tipo Pessoa. Também criamos um método Pesquisar que recebe por parâmetro um identificador e retorna o objeto correspondente da lista. O que deve ser verificado nesse método é que o mesmo retorna um objeto anônimo com duas propriedades: DataNascimento e Telefone. Repare que o tipo de retorno é um object, logo, será necessário um cast para o tipo original para acesso às propriedades.

Agora vamos criar nosso ASPX que deverá conter um componente DropDownList para receber a lista de Pessoas, ao selecionar uma das opções o controle executará um PostBack para resgatar as informações de Data de Nascimento e Telefone e apresentar as mesmas para o usuário.

<p>Pessoas:</p> <asp:DropDownList ID="dropPessoas" runat="server" DataTextField="nome" DataValueField="id" AutoPostBack="True" OnSelectedIndexChanged="dropPessoas_SelectedIndexChanged" /> <p><asp:Literal ID="liDataNascimento" runat="server" /></p> <p><asp:Literal ID="liTelefone" runat="server" /></p>
Listagem 2. Conteúdo da página ASPX

E o Code Behind:

protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) CarregarDropDown(); } void CarregarDropDown() { dropPessoas.DataSource = Pessoa.Carregar(); dropPessoas.DataBind(); } protected void dropPessoas_SelectedIndexChanged(object sender, EventArgs e) { object x = Pessoa.Pesquisar(Convert.ToInt32(dropPessoas.SelectedValue)); }
Listagem 3. Code behind da página

Note que no evento “dropPessoas_SelectedIndexChanged” chamamos o método Pesquisar passando o id da pessoa selecionada, o problema é, como acessamos a propriedades DataNascimento e Telefone?

Primeiro vamos criar o método que consegue fazer o cast para o tipo anônimo criado:

protected T Cast<T>(object obj, T tipo) { return (T)obj; }
Listagem 4. Método para realização do cast

Entendendo o código:

Criamos um método genérico que recebe um objeto a ser convertido, e um segundo parâmetro que receberá um objeto do mesmo tipo para o qual queremos converter o objeto do primeiro parâmetro, faremos isso para podermos fazer o compilador inferir o tipo em T e fazer o cast necessário.

Agora você vai perguntar, mas como vou passar um objeto do mesmo tipo anônimo criado pela minha consulta LINQ?

A resposta está na criação de outro objeto anônimo com as mesmas propriedades criadas para o objeto retornado na consulta LINQ, para o compilador, 2 objetos anônimos com as mesmas propriedades são da mesma classe anônima:

protected void dropPessoas_SelectedIndexChanged(object sender, EventArgs e) { object x = Pessoa.Pesquisar(Convert.ToInt32(dropPessoas.SelectedValue)); var obj = Cast(x, new { DataNascimento = DateTime.Now, Telefone = "" }); liDataNascimento.Text = obj.DataNascimento.ToShortDateString(); liTelefone.Text = obj.Telefone; }
Listagem 5. Criando objetos da classe anônima

Note que chamamos o método Cast passando primeiro o objeto que queremos converter, e em segundo passamos um novo objeto anônimo com as mesmas propriedades (os valores não importam) do objeto sendo apontado por x. Dessa forma a variável obj será do tipo anônimo desejado e as propriedades DataNascimento e Telefone estarão acessíveis.

Chamamos essa técnica de “Cast por Exemplo”, pois ajudamos o compilador a inferir um tipo passando outro objeto com a mesma estrutura como exemplo.

Com o C# 4.0 podemos usar os tipos dinâmicos para facilitar essa tarefa como mostrado abaixo:

protected void dropPessoas_SelectedIndexChanged(object sender, EventArgs e) { dynamic x = Pessoa.Pesquisar(Convert.ToInt32(dropPessoas.SelectedValue)); liDataNascimento.Text = x.DataNascimento.ToShortDateString(); liTelefone.Text = x.Telefone; }
Listagem 6. Utilização de tipo dinâmico

Como o tipo dinâmico só é testado em tempo de execução, o compilador irá descobrir que aquela instância contém as propriedades informadas e irá resgatar os valores normalmente.

Conclusão

Tipos anônimos, genéricos e tipos dinâmicos são pequenos exemplos das possibilidades que o C# nos oferece, é importante conhecer a fundo esses recursos para o máximo aproveitamento em diversas situações.

Ebook exclusivo
Dê um upgrade no início da sua jornada. Crie sua conta grátis e baixe o e-book

Artigos relacionados