LINQ, Reflection y C#
Todos los programadores de C# y .NET sabemos lo que nos puede ofrecer LINQ y como nos simplifica la vida cuando trabajamos con él.
También, muchos de nosotros sabemos lo que nos ofrece Reflection a la hora de «jugar» con los entresijos de una librería o ensamblado.
El único problema es que a veces trabajar con Reflection es un poco duro, mientras que trabajar con LINQ es realmente ágil y sencillo.
Así que, ¿qué tal si mezclamos la potencia de ambas características para al menos, ayudarnos y facilitarnos la vida cuando trabajamos con Reflection?.
Pues nada… eso es lo que mostraré en esta entrada.
Empecemo entonces ya con la parte práctica que demuestre como podemos hacerlo.
Para ello, voy a preparar lo siguiente:
- Un par de clases que formarán parte de una librería o ensamblado donde meteré algunos métodos, propiedades, constructores… nada rebuscado para esta demostración. Algo realmente simple para no perdernos.
- Luego, crearé una aplicación de consola que cargará el ensamblado con Reflection, y a través de LINQ, extraeremos por consola los constructores y métodos de las dos clases que están dentro del ensamblado. Todo esto lo extraeremos combinando LINQ y Reflection.
Empecemos por lo tanto por nuestra clase o ensamblado que tendrá el siguiente aspecto:
En primer lugar, escribiremos la clase ClassFoo:
namespace FooLibrary { using System; public class ClassFoo { private readonly DateTime _dateStamp; public ClassFoo() { this._dateStamp = DateTime.UtcNow; } public override string ToString() { return this._dateStamp.ToString("dd/MM/yyyy HH:mm:ss"); } } }
A continuación seguiremos por la clase MyClass:
namespace FooLibrary { using System; public class MyClass { public string Name { get; set; } public int Age { get; set; } public MyClass(string name, int age) { if (String.IsNullOrEmpty(name)) throw new ArgumentNullException("name"); this.Name = name; this.Age = age; } public string GetMessage() { return $"Hello {this.Name}"; } public string GetAge() { return $"{Name}, you are {this.Age} years old"; } } }
Como podemos apreciar, estas clases tienen un poco de todo, pero no tienen nada de especial.
Ahora vamos con la aplicación de consola que es la que realmente nos interesa y que demuestra el uso de LINQ junto con Reflection.
Nuestro proyecto de consola, y en nuestro caso la clase Program, quedará de la siguiente forma:
namespace Blog_DotNet_Linq_Reflection { using System; using System.Linq; using System.Reflection; public class Program { public static void Main(string[] args) { Console.WriteLine("Program started"); Console.WriteLine(); var assembly = Assembly.Load("FooLibrary"); var assemblyConstructors = from type in assembly.GetTypes() from constructors in type.GetConstructors() group constructors.ToString() by type.ToString(); var assemblyMethods = from type in assembly.GetTypes() from methods in type.GetMethods() group methods.ToString() by type.ToString(); var consoleForegroundColor = Console.ForegroundColor; foreach (var constructors in assemblyConstructors) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("Type: {0}", constructors.Key); Console.ForegroundColor = ConsoleColor.Yellow; foreach (var constructor in constructors) { Console.WriteLine("\t{0}", constructor); } var methods = from assemblyMethod in assemblyMethods where assemblyMethod.Key == constructors.Key select assemblyMethod; Console.ForegroundColor = ConsoleColor.Cyan; foreach (var method in methods) { foreach (var type in method) { Console.WriteLine("\t{0}", type); } } Console.WriteLine(); } Console.ForegroundColor = consoleForegroundColor; Console.WriteLine("Press any key to close the App"); Console.ReadLine(); } } }
Nuestra aplicación en ejecución queda representada de la siguiente forma:
Analizando el código de nuestra aplicación de consola, vemos que utilizamos System.Linq y System.Reflection como ensamblados principales que nos harán el juego de usar LINQ y Reflection.
También vemos que cargamos el ensamblado «FooLibrary» que habíamos preparado anteriormente con dos clases, ClassFoo y MyClass.
Es muy importante, para este ejemplo, que el ensamblado esté en el mismo directorio en el que se está ejecutando nuestra aplicación de consola (el directorio bin si lo ejecutamos desde Visual Studio).
Luego, con instrucciones de LINQ, extraemos del ensamblado, los constructores de las clases que encuentra dentro del ensamblado por un lado, y los métodos de cada clase por otro lado.
En mi caso lo he separado en dos sentencias LINQ para no complicar el proceso y que sea lo más simple posible desde el punto de vista del entendendimiento en el uso de LINQ y Reflection.
Y para finalizar, recorremos cada elemento obtenido por LINQ, y lo mostramos por pantalla.
Como ves, LINQ nos simplifica mucho la farragosa tarea de trabajar con Reflection.
También, podemos utilizar expresiones Lambda para lograr el mismo propósito, pero esto no lo trataré. Simplemente comentarlo por si a alguien le apetece hacer lo mismo de otra manera, y comentar que es posible igualmente.
Podrás acceder al código fuente de este ejemplo en mi repo de GitHub, en este enlace.
¡Happy Coding!