C# — Criando tipos personalizados de retorno em Runtime

Andre Santarosa
4 min readMay 25, 2019
Photo by Fatos Bytyqi on Unsplash

As vezes chegamos em uma situação no nosso dia a dia como desenvolvedor que nos deparamos com um problema e coçamos a cabeça, pensamos mais um pouco, coçamos a cabeça novamente e chegamos a conclusão que talvez seja necessário centenas de linhas de código para entregar uma funcionalidade específica. Sempre que isso acontece eu paro e penso um pouco antes de prosseguir, pois, obviamente, centenas de linhas são muito mais difíceis de manter do que algumas dezenas.

Esses tempos atrás passei por um desses momentos. Precisávamos de um retorno com alguns itens e suas propriedades, de primeira pensei em criar uma Lista<T> de objetos contendo uma propriedade Nome e uma outra Valor ou ainda usar uma tupla. O problema é que em ambos os casos o retorno seria:

E o que eu precisava era esse:

A primeira vista não parece grande coisa, era só colocar “na mão” os nomes em um retorno personalizado e estava tudo resolvido, entretanto nós tínhamos uma quantidade considerável de entidades e cada uma delas com uma quantidade considerável de propriedades, propriedades essas que poderiam sofrer adições ou remoções. Lembra das centenas de linhas de códigos que comentei acima? Então, achei que, infelizmente, seria essa a solução. Entretanto resolvi pesquisar mais um pouco, deveria haver uma forma mais inteligente de fazer o serviço. Depois de algumas horas de pesquisa me deparei com uma classe chamada ExpandoObject que acabou por resolver o problema de uma forma muito simples e prática .

A classe ExpandoObject foi introduzida no C# 4.0 e veio junto com a implementação do tipodynamic que faz parte do DLR (Dynamic Language Runtime) do .NET Framework . O tipo dynamic tem um comportamento bem interessante. Ele é um tipo estático, assim como os outros tipos do C#, entretanto ele não é verificado durante a compilação e seu conteúdo só vai ser lido em runtime, ou seja, durante a escrita do código, um objeto dynamic pode ser qualquer coisa e isso abre possibilidades imensas! Em breve farei um post mais profundo sobre o dynamic, mas por enquanto vamos focar no ExpandoObject e nas saídas customizadas.

Para facilitar a explicação, tomemos como exemplo a tabela abaixo

O que precisamos nesse caso é o seguinte: Ao passarmos o nome do prato o retorno deve possuir seus ingredientes como chave e trazer o valor de cada um deles.

Para representr a tabela acima temos a classe Item.cs

Abaixo vamos criar:

  • Uma propriedade que conterá todos os ingredientes
  • Um método que popula os ingredientes
  • Um outro método que filtra e retorna os ingredientes baseado no nome do prato

Agora a parte legal começa a rolar… Abaixo vamos criar o método que receberá todos os ingredientes, percorrerá cada um deles e fará uma chamada para adicionar a propriedade e o valor ao objeto retorno customizado. Repare que passamos o expandoObject por referencia para preservar as suas propriedades e referencias de memória.

E finalmente o método que faz a mágica acontecer!

Simples assim? Simples assim! Fazemos um casting do ExpandoObject para um dicionário e adicionamos ou atualizamos as propriedades/valores das chaves. Como o tipo ExpandoObject é dinamico, ele aceita criação de propriedades e métodos em runtime.

Método main do nosso programa:

Quando passamos cachorro_quente como parâmetro para o método ele filtra apenas os ingredientes pertencentes ao cachorro_quente , passa para o método RetornaCusto que gera o objeto customizado e depois serializamos a saída.

Com cachorro_quente a saída fica:

Com cheeseburger

Aí você me pergunta, não seria mais fácil ter criado só o dicionário ao invés de dar essa volta utilizando objetos dinâmicos e outras funcionalidades?
A resposta é sim, mas não ao mesmo tempo. O dicionário é um esquema chave-valor, e prove muito menos funcionalidades que uma objeto completo, podendo conter apenas propriedades, lembre-se que o ExpandoObject pode conter um tipo inteiro ali dentro, incluindo propriedades e métodos que podem ser chamados via Reflection e interagir com todo esse objeto, o que proporciona flexibilidade e uma infinidade de possibilidades.

Abaixo o código completo:

Se você leu até aqui, obrigado e até o próximo artigo! =)

--

--

Andre Santarosa

C#/.Net Senior Developer @Viatel Ireland. Likes to cook on the weekends and to play old songs on the guitar.