Clik here to view.

Volvemos otra semana más hablando de le reflexión en C#, y hoy toca hablar de los constructores. Como recordatorio, las últimas semanas hemos dado unas pinceladas sobre la reflexión y también hemos visto cómo podemos aprovecharla en los ensamblados.
Hoy vamos a seguir buceando un poco en la potencia que nos aporta la reflexión, en este caso para los constructores. Como vimos, es posible crear instancias de clases mediante reflexión utilizando:
var assembly = Assembly.GetAssembly(typeof(Program));
//Creamos el objeto de manera dinámica
var objetoDinamico = assembly.CreateInstance("PostReflexion.ClaseEjemplo",
false,
BindingFlags.ExactBinding,
null,
new object[] { 2 }, /*Argumentos del constructor*/
null,
null);
Pero esto tiene un mayor coste si vamos a utilizar varias veces el mismo constructor. Esto es porque la reflexión, pese a ser un proceso potente, es caro. En la siguiente tabla se puede comparar los resultados entre instanciar el mismo objeto con el código anterior, o buscando su ConstructorInfo, almacenándolo en memoria y llamando solo a este (no te preocupes, ahora vamos a ver que es el ConstructorInfo).
Clik here to view.

De los datos de la imagen anterior, se puede ver claramente que el proceso de creación de un objeto es hasta 376 veces más lento usando Assembly.CreateInstance, mientras que usando un ConstructorInfo.Invoke solo lo es 60 veces. esto es porque obligamos a ejecutar todo el proceso de búsqueda del constructor de la clase cada vez que queremos crear un objeto (y recordemos la que reflexión es cara, por eso llamar al constructor de la clase siempre es más rápido).
Una vez vistos los datos, está claro que siempre que podamos, lo mejor es no utilizar reflexión, pero si vamos a usarla y encima de manera repetida, es mejor almacenar las partes que necesitemos y no tener que buscarlas cada vez.
Obteniendo los constructores por reflexión
Vale, llegados a este punto, tenemos una cosa clara:
«Un gran poder conlleva una gran responsabilidad»
Tío Ben – Spiderman
Dentro de Assembly, también podemos obtener las declaraciones de tipos («Type«), donde se encuentra toda la información de la definición:
className = "PostReflexion.ClaseEjemplo";
var assembly = Assembly.GetAssembly(typeof(Program));
var type = assembly.GetType(className);
Y es aquí donde empieza «la magia»… Este objeto «Type» nos permite bucear en todos los recovecos que contiene y obtener entre otras cosas un ContructorInfo por cada constructor que se haya definido en el código (en las siguientes entradas iremos viendo el resto de sus posibilidades).
var className = "PostReflexion.ClaseEjemplo";
var assembly = Assembly.GetAssembly(typeof(Program));
var constructors = assembly.GetType(className).GetConstructors();
O incluso, nos permite acceder al que coincida con el tipo de argumentos (y el orden) que le pedimos:
var className = "PostReflexion.ClaseEjemplo";
var assembly = Assembly.GetAssembly(typeof(Program));
var type = assembly.GetType(className);
//Contructor con parametro int
var constructorConParametros = type.GetConstructor(new[] { typeof(int) });
//Constructor genérico
var constructorSinParametros = type.GetConstructor(Type.EmptyTypes);
Y sin darnos cuenta, ¡ya tenemos nuestro ConstructorInfo listo! Ahora solo nos queda llamar a su método Invoke pasándole como parámetro un array de objetos que cumpla con la firma, es decir, si el constructor espera un «int», le pasaremos un new object[] {int}, si espera un int y un string, new object[] {int,string} ,etc:
var className = "PostReflexion.ClaseEjemplo";
var assembly = Assembly.GetAssembly(typeof(Program));
var type = assembly.GetType(className);
//Contructor con parametro int
var constructorConParametros = type.GetConstructor(new[] { typeof(int) });
//Creamos el objeto de manera dinámica
var objetoDinamicoConParametros = constructorConParametros.Invoke(new object[] { 2 });
Lo que sí es un poco más «raro», es cuando queremos buscar los constructores por reflexión para conseguir el genérico, que hay que utilizar «Type.EmptyTypes» a la hora de buscarlo (y no pasarle nada en el Invoke)
var className = "PostReflexion.ClaseEjemplo";
var assembly = Assembly.GetAssembly(typeof(Program));
var type = assembly.GetType(className);
//Constructor genérico
var constructorSinParametros = type.GetConstructor(Type.EmptyTypes);
//Creamos el objeto de manera dinámica
var objetoDinamicoSinParametros = constructorSinParametros.Invoke(new object[] { });
¡Vamos a probarlo!
Para probar que funciona, yo he definido una clase con dos constructores así:
public class ClaseEjemplo
{
private int _valor;
public ClaseEjemplo(int valor)
{
_valor = valor;
}
public ClaseEjemplo()
{
_valor = 0;
}
public int Multiplicar(int por)
{
Console.WriteLine($"Llamada a {nameof(Multiplicar)} con parámetro {por}");
return _valor * por;
}
}
Y con este código, voy a llamar a sus dos constructores y y a su método Multiplicar (en las próximas entradas veremos en detalle cómo). Según el código, cuando cree la instancia con el constructor genérico, el resultado de llamar a Multiplicar siempre será 0, ya que cualquier número por 0 es 0:
var className = "PostReflexion.ClaseEjemplo";
var assembly = Assembly.GetAssembly(typeof(Program));
var type = assembly.GetType(className);
//Obtenemos los constructores
//Contructor con parametro int
var constructorConParametros = type.GetConstructor(new[] { typeof(int) });
//Constructor genérico
var constructorSinParametros = type.GetConstructor(Type.EmptyTypes);
//Creamos el objeto de manera dinámica
var objetoDinamicoConParametros = constructorConParametros.Invoke(new object[] { 2 });
var objetoDinamicoSinParametros = constructorSinParametros.Invoke(new object[] { });
// Creamos una referencia al método
var m = assembly.GetType(className).GetMethod("Multiplicar");
//Llamamos al método pasandole el objeto creado dinámicamente y los argumentos dentro de un object[]
var retConstructorParamatrizado = m.Invoke(objetoDinamicoConParametros, new object[] { 3 });
var retConstructorGenerico = m.Invoke(objetoDinamicoSinParametros, new object[] { 3 });
Console.WriteLine($"El retorno de la función con constructor parametrizado es: {retConstructorParamatrizado}");
Console.WriteLine($"El retorno de la función con constructor genérico es: {retConstructorGenerico}");
Tras ejecutar el programa, efectivamente podemos comprobar que el resultado es el esperado:
Clik here to view.

Con esto hemos visto una manera de crear objetos de manera dinámica «eficientemente» gracias a la reflexión en constructores. En las siguientes entradas, seguiremos desgranando como funciona esta maravillosa herramienta que es la reflexión.
He actualizado el repositorio de GitHub con el código para añadir el ejemplo de reflexión en constructores.
**La entrada La potencia de la Reflexión en C# (Parte 3: Constructores) se publicó primero en Fixed Buffer.**