Metaprogramação em C#: da reflexão à geração de código

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Metaprogramação em C#: Quando o código escreve código



Imagine que você é um arquiteto que não constrói apenas uma casa, mas um robô-construtor que ergue paredes, passa a fiação elétrica e pinta as fachadas sozinho. No mundo do C#, esse "robô" é a metaprogramação — a arte de escrever programas que criam, analisam ou modificam outros programas (ou a si mesmos) durante a execução.



Por que isso é necessário? Imagine que você está escrevendo dezenas de classes semelhantes para trabalhar com JSON, criando sistemas complexos de plugins ou com preguiça de chamar manualmente centenas de métodos por reflexão. A metaprogramação em C# permite automatizar tarefas rotineiras, criar frameworks flexíveis e acelerar o desenvolvimento várias vezes. Hoje, vamos abordar os três pilares dessa técnica: reflexão, árvores de expressão e geração dinâmica de código.



Este artigo é para quem já escreve em C# com confiança, mas quer olhar sob o capô do CLR e aprender a magia que diferencia um sênior de um pleno. Vamos nessa!



Reflexão (Reflection): Raio-X do seu código



A reflexão é a base da metaprogramação em C#. Ela permite obter informações sobre tipos, métodos, propriedades e campos durante a execução, além de invocá-los dinamicamente. Imagine que você olha para um objeto como se fosse um livro aberto e pode ler qualquer página dele.



Obtendo informações sobre o tipo



A maneira mais simples é usar a palavra-chave typeof ou o método GetType():



Type stringType = typeof(string);Console.WriteLine($"Nome: {stringType.Name}"); // StringConsole.WriteLine($"Namespace: {stringType.Namespace}"); // SystemConsole.WriteLine($"É uma classe? {stringType.IsClass}"); // True


Invocação dinâmica de métodos



Suponha que você tenha uma classe Calculator e queira chamar seu método Add, cujo nome só é conhecido em tempo de execução (por exemplo, a partir de uma configuração):



public class Calculator{    public int Add(int a, int b) => a + b;}

// Usando reflexãoCalculator calc = new Calculator();Type calcType = typeof(Calculator);MethodInfo? addMethod = calcType.GetMethod("Add");

if (addMethod != null){ int result = (int)addMethod.Invoke(calc, new object[] { 5, 3 }); Console.WriteLine($"Resultado: {result}"); // 8}


Quando a reflexão é útil?

  • Serialização / Desserialização — bibliotecas como Newtonsoft.Json usam reflexão ativamente.
  • Plugins — carregar assemblies externos e chamar seus métodos.
  • Testes — acesso a campos e métodos privados (embora seja melhor não fazer isso).


Importante! A reflexão é uma operação lenta. Se você estiver chamando o mesmo método milhares de vezes, considere armazenar em cache o MethodInfo ou usar delegates.



Árvores de Expressão (Expression Trees): Código como dados



Árvores de expressão são uma forma de representar código como uma estrutura de dados (uma árvore). Você pode analisar, modificar e até compilar esse código "em tempo real". É uma ferramenta poderosa para criar ORMs (Entity Framework), validadores e consultas dinâmicas.



Criando uma árvore simples



Em vez de escrever uma lambda x => x * 2, nós a construímos manualmente:



using System.Linq.Expressions;

// Criando o parâmetro xParameterExpression param = Expression.Parameter(typeof(int), "x");// Criando a constante 2ConstantExpression constant = Expression.Constant(2);// Criando a multiplicação x * 2BinaryExpression body = Expression.Multiply(param, constant);// Montando tudo em uma lambda: x => x * 2Expression<Func<int, int>> lambda = Expression.Lambda<Func<int, int>>(body, param);

// Compilando e executandoFunc<int, int> compiled

Blogs

Book Recommendations