lunes, 24 de diciembre de 2007

Reflection en .NET Framework

CHenry [chenry@hha.sld.cu]

Una gran importancia reporta la característica de .Net en su capacidad para descubrir información de “tipo” en tiempo de ejecución. De forma segura se puede usar el espacio de nombres “reflection” para poder ver en tiempo de ejecución la información de “tipo” que contienen los ensamblados, de esta forma se pueden enlazar con objetos o incluso una herramienta sumamente potente la cual es la posibilidad para generar código en tiempo de ejecución. Esta tecnología es una extensión de la tecnología COM la cual podría ser abordada en otro articulo(Es sumamente interesante su arquitectura e incluso los disímiles usos que nos puede brindar).

En ocasiones se nos plantean determinadas situaciones en que nos urge utilizar un objeto sin llegar a comprender realmente lo que realiza este objeto. El namespace reflection(a partir de ahora nos referiremos a el como Reflexión) nos permite obtener determinada información de un objeto y con esta poder conocer sus propiedades, métodos, constructores, eventos y variables. De forma directa podemos usar la clase System.Type (por su importancia en el uso de la reflexión veremos un barniz de la clase Type) para examinar el ensamblado y de esta forma poder usar métodos como GetMethods () y GetProperties () que devuelven información del ensamblado en cuestión. Esta información es sumamente interesante ya que permite desde llamar el método MethodsInfo (), el cual nos devuelve una lista de parámetros, hasta ejecutar (llamar) a métodos en el ensamblado a través del método Invoke ().

SYSTEM.TYPE
Esta clase abstracta actúa como un portal para la API de reflexión lo que permite el acceso a los metadatos, esta clase representa un tipo del “Sistema completo de tipos”(CTS). Este sistema nos permite examinar objetos de todos los lenguajes de la familia .NET. De esta forma todos los objetos usan el mismo entorno en tiempo de ejecución y sistema de tipos facilitando esto la obtención de información del objeto y del tipo.

Nota: Una de las características más interesantes del Type es su capacidad para crear objetos dinámicamente y usarlos en tiempo de ejecución.

Obtener la información de tipo.
Ahora veremos tres formas de obtener la información de tipo de un objeto:
1. Usando un nombre de tipo.
2. Usando un nombre de proceso.
3. Especificando un nombre de ensamblado.
Todas estas variante por detrás de esta capa de abstracción realizan las mismas tareas es decisión del programador el uso de una o de otra en dependencia de su aplicación, aquí les van.

Recuperación de tipos por el nombre

Con solo especificar el nombre del tipo se puede consultar casi todos los aspectos del objeto. Se puede extraer información de la detallada como si es una clase, el tipo de su sistema base y otras propiedades (Ver MSDN).
Como ejemplo de este métodos creamos una sencilla aplicación C# consola que nos permita ver algunas propiedades de la clase System.String.

Código #1 como listar información mediante el nombre

using System;
using System.Reflection;

class ExtractNameType
{
  public static void Main()
  {
     Type t = Type.GetType("System.String");
     Console.WriteLine("Name: {0}",t.Name);
     Console.WriteLine("Underlying System Type: {0}",t.UnderlyingSystemType);
     Console.WriteLine("Is Class: {0}",t.IsClass);
  }
}

Al correr esta aplicación nos muestra que System.String es el tipo de sistema base, y que este objeto es una clase.
Ahora se preguntara para Ost… nos sirve esto bueno al parecer no es mucho ? pero bien pongamos un ejemplo imagine que esta creando una aplicación que necesita generar instrucciones “insert” para introducir información en SQL Server. Escribir una gran cantidad de información requiere gran cantidad de tiempo, pero si se usa Reflexión y la clase Type se pudiera examinar el tipo subyacente de cada fragmento de información que quiera insertar en SQL Server y poder describir esos tipos a un tipo de datos SQL Server valido, lo que simplificaría mucho el proceso de generar mediante programación las instrucciones “insert”.

Recuperación de tipos mediante instancias

En este caso en vez de usar el nombre de tipo se usa una instancia de este para conseguir la información.

Código # 2 Por instancia

using System;
using System.Reflection;

class ExtractNameType
{
  public static void Main()
  {
     String obj = "Carlos Henry";
     Type t = obj.GetType();
     Console.WriteLine("Name: {0}",t.Name);
     Console.WriteLine("Underlying System Type: {0}",t.UnderlyingSystemType);
     Console.WriteLine("Is Class: {0}",t.IsClass);
  }
}

En esta aplicación se crea una instancia de de la clase String con el nombre obj a la cual posteriormente se le llama al método Gettype() , la información obtenida por esta vía el la misma que la que se obtuvo en Código #1.

Recuperación de tipos en un ensamblado

Y ahora la variante mas interesante, esta se encarga incluso de recuperar información de un objeto ya ensamblado ya este dentro de un ejecutable (.exe) o una biblioteca de vínculos dinámicos (.dll), en el código siguiente les mostraremos como obtener información acerca de nuestra propia aplicación.

Código # 3 Recuperar información de nuestra aplicación.

using System;
using System.Reflection;
using System.Diagnostics;

class AssemblyType
{
  public static void Main(string [] args)
  {
     Process p = new Process.GetCurrentProcess();
     string name= p.ProcessName + ".exe";
     Console.WriteLine("Looking: {0}",name);
     Assembly a = new Assembly.LoadFrom(name);
     Type [] types = a.GetTypes();
     foreach(Type t in types)
     {
        Console.WriteLine("Type: {0}\n",t.FullName);
        Console.WriteLine("/t Base Class: {0}",t.BaseType.FullName);
     }
  }
}

En el código anterior se muestran algunos elementos nuevos, el tipo Process se usa para echarle una ojeada a los procesos que se están ejecutando. En esta aplicación lo utilizamos para obtener el nombre de nuestra aplicación y luego agregamos .exe al final del nombre para que se pueda examinar el ensamblado. Esto lo hacemos para que este aplicación funcione independiente del nombre que le pongamos al escribirla. Al correr esta aplicación no se nos brinda mucha información ya que la misma solo tiene una le rogamos que juegue un poco con este código probando cosas como otros métodos en la clase Type así como el tipo Process que se les presento en este código también.

Hasta aquí un pequeño background de este tema por falta de tiempo no puedo ponerles un ejemplo mas detallado pero prometo escribir algo de código en un próximo articulo y quizás algo de cómo Generar código dinámicamente mediante Reflexion.

Nota: Las aplicaciones que por su estructuración y funcionalidad tengan que programarse de forma tal que deban ser upgradeadas en tiempo de ejecución, ejemplo aplicaciones a las que se le pueden agregar Plugins pueden implementar este sistema usando Reflexion.



Artículos relacionados


No hay comentarios: