Metaprogramación en C#: de la reflexión a la generación de código

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Metaprogramación en C#: Cuando el código escribe código



Imagina que eres un arquitecto que no solo construye una casa, sino un robot constructor que él mismo levanta paredes, tiende el cableado y pinta las fachadas. En el mundo de C#, este "robot" es la metaprogramación — el arte de escribir programas que crean, analizan o modifican otros programas (o a sí mismos) durante la ejecución.



¿Para qué sirve esto? Imagina que escribes decenas de clases similares para trabajar con JSON, creas sistemas complejos de plugins o te da pereza llamar manualmente cientos de métodos mediante reflexión. La metaprogramación en C# permite automatizar tareas rutinarias, crear frameworks flexibles y acelerar el desarrollo varias veces. Hoy analizaremos los tres pilares de esta técnica: reflexión, árboles de expresión y generación dinámica de código.



Este artículo es para quienes ya escriben con soltura en C#, pero quieren mirar bajo el capó del CLR y aprender la magia que diferencia a un senior de un mid-level. ¡Allá vamos!



Reflexión (Reflection): Rayos X para tu código



La reflexión es la base de la metaprogramación en C#. Permite obtener información sobre tipos, métodos, propiedades y campos durante la ejecución, así como invocarlos dinámicamente. Imagina que miras un objeto como si fuera un libro abierto y puedes leer cualquier página.



Obtener información sobre un tipo



La forma más sencilla es usar la palabra clave typeof o el método GetType():



Type stringType = typeof(string);Console.WriteLine($"Nombre: {stringType.Name}"); // StringConsole.WriteLine($"Espacio de nombres: {stringType.Namespace}"); // SystemConsole.WriteLine($"¿Es una clase? {stringType.IsClass}"); // True


Invocación dinámica de métodos



Supongamos que tienes una clase Calculator y quieres llamar a su método Add, cuyo nombre solo se conoce en tiempo de ejecución (por ejemplo, desde una configuración):



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

// Usamos reflexiónCalculator 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}


¿Cuándo es útil la reflexión?

  • Serialización / Deserialización — bibliotecas como Newtonsoft.Json usan reflexión activamente.
  • Plugins — cargar ensamblados externos y llamar a sus métodos.
  • Pruebas — acceso a campos y métodos privados (aunque es mejor no hacerlo).


¡Importante! La reflexión es una operación lenta. Si llamas al mismo método miles de veces, considera almacenar en caché el MethodInfo o usar delegados.



Árboles de expresión (Expression Trees): Código como datos



Los árboles de expresión son una forma de representar código como una estructura de datos (un árbol). Puedes analizar, modificar e incluso compilar este código "sobre la marcha". Es una herramienta poderosa para crear ORM (Entity Framework), validadores y consultas dinámicas.



Creación de un árbol simple



En lugar de escribir la lambda x => x * 2, la construimos manualmente:



using System.Linq.Expressions;

// Creamos el parámetro xParameterExpression param = Expression.Parameter(typeof(int), "x");// Creamos la constante 2ConstantExpression constant = Expression.Constant(2);// Creamos la multiplicación x * 2BinaryExpression body = Expression.Multiply(param, constant);// Lo ensamblamos todo en una lambda: x => x * 2Expression<Func<int, int>> lambda = Expression.Lambda<Func<int, int>>(body, param);

// Compilamos y ejecutamosFunc<int, int> compiled

Blogs

Book Recommendations