Cualquier cosa que valga la pena se hace en equipo

Cualquier cosa que valga la pena se hace en equipo

viernes, 4 de junio de 2010

Programacion Reflexiva . PARTE II



El enfoque en C#
El cargador del lenguaje común administra lo que se denominan DOMINIO de APLICACIONES. El lenguaje común es el CONTENEDOR que aísla al programa del SO. Cualquier aplicación desarrollada en .NET no se comunicara directamente con APIs de WIN32, tal como lo hacíamos anteriormente sino a través de funciones, servicios, etc. del contenedor.- EL DOMINIO de la APLICACIÓN es el contorno o los limites en los que trabajan aquellos objetos que pertenecen al mismo alcance de aplicación.- La administración de este cargador incluye la carga de cada assembly en el dominio de aplicación adecuado y controla la disposición y arreglo en memoria del tipo de jerarquía en cada assembly.-
Veamos unos ejemplos.-

Ejemplo I:
En este caso haremos un proyecto que contendra las clases que queremos acceder a traves de Reflection.- Es por eso que utilizamos el metodo estatico: Assembly.GetExecutingAssembly(); para poder tener un objeto de la clase Assembly. Este es el modo de hacerlo cuando lo que necesitamos es un objeto de una clase que esta dentro del codigo actualmente en ejecucion.- Obtenemos un objeto de la clase Assembly de este modo : Assembly assem = new Assembly()) Este el objeto creado nos permitira, por ejemplo, instanciar objetos de las clases contenidas en el assembly.- Para eso el primer paso es:


¿Como acceder a una clase del assembly?

El objeto de la clase Assembly tiene un metodo llamado CreateInstance().
Este método admite como parámetro el nombre de una clase así como los parámetros que necesitase su constructor.
Este método es uno de los métodos capitales de la programación reflexiva ya que nos permite a través de un texto que representa el nombre de la clase, obtener un objeto que es una instancia de la misma.-
El codigo siguiente muestra la utilizacion del metodo

CreateInstance():

// Crear un objeto de la clase Ejemplo2, desde el assembly que la contiene // El constructor de Ejemplo2 necesita un parametro que es un entero //

Object o = assem.CreateInstance("Ejemplo2", false, BindingFlags.ExactBinding, null, new Object[] { 2 }, null, null);

Observe que se accede a una clase y se instancia un objeto de la misma a traves de un parametro que es un texto ("Ejemplo2").-
Observe tambien que uno de los parametros de CreateInstance() es un array de Object al que se le envian los parametros QUE EL CONSTRUCTOR de la clase necesita.
Esto es: No es suficiente con conocer el nombre de clase en el assembly sino que es preciso conocer algo mas de ella.
Esto es similar a lo que nos sucede en el programa C que vimos al inicio en el que debemos conocer algo del PROTOTIPO de la funcion para hacer una llamda exitosa.-

¿Como acceder a un metodo de la clase?

Ahora bien, tenemos un objeto O que es una instancia de una clase del assembly. ¿Como hacemos ahora para acceder a un metodo de dicha clase?
El handler al assembly (assem) tiene un metodo llamado GetType que obtiene información sobre el tipo exacto que se produce en tiempo de ejecucion para el objeto corriente.-
Es decir GetType retorna un tipo (Type). La clase Type es la base de reflection para acceder a la metada del objeto. Type es una interfaz que tiene distintas implementaciones. La que aquí no sinteresa, tiene un metodo llamado GetMethod() que, tomando como parametro el nombre del metodo, nos trae información del mismo. Asi:

MethodInfo m = assem.GetType("Ejemplo2").GetMethod("MetodoDeEjemplo");

Obtenida la información sobre el metodo, se lo puede invocar a traves del metodo Invoke de MethodInfo .
Igual que en el caso anterior, si bien es posible obtener acceso al metodo a traves de un literal (en este caso el nombre del metodo es : MetodoDeEjemplo ), el uso posterior del metodo requiere conocer cuales son los parametros adecuados.

Object ret = m.Invoke(o, new Object[] { 42 });

En este caso el entero 42 se corresponde al tipo de datos que corresponde al Metodo, MetodoDeEjemplo EL retorno que produce Invoke es un Object.

EL uso posterior del mismo sera parte de la logica de negocios del programa.-

Arme un proyecto de consola simple y coloque el código indicado en un modulo cs (C#)
















Y pruebe este codigo:

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Security.Permissions;
using System.Configuration;



class Ejemplo2
{
private int factor;

public Ejemplo2(int f)
{
factor = f;
}

public int MetodoDeEjemplo(int x)
{
Console.WriteLine("\nEjemplo2.MetodoDeEjemplo({0}) ejecutado.", x);
return x * factor;
}

public string OtroMetodo(string a)
{

StringBuilder st = new StringBuilder("A este dato le concateno: ");
Console.WriteLine("\nEjemplo2.OtroMetodo({0}) ejecutado.", a);
st.Append(a);
return st.ToString();
}


}

public class ejecuta
{

public static void Main()
{

Assembly assem = Assembly.GetExecutingAssembly();

Console.WriteLine("Nombre completo del Assembly:");
Console.WriteLine(assem.FullName);

//
AssemblyName assemName = assem.GetName();
Console.WriteLine("\nName: {0}", assemName.Name);
Console.WriteLine("Version: {0}.{1}",
assemName.Version.Major, assemName.Version.Minor);

Console.WriteLine("\nAssembly CodeBase:");
Console.WriteLine(assem.CodeBase);

// Crear un objeto de la clase Ejemplo2, desde el assembly que la contiene
//El constructor de Ejemplo2 necesita un parametro que es un entero
//
Object o = assem.CreateInstance("Ejemplo2", false,
BindingFlags.ExactBinding,
null, new Object[] { 2 }, null, null);

// Ahora apuntamos a un metodo del objeto:

MethodInfo m = assem.GetType("Ejemplo2").GetMethod("MetodoDeEjemplo");
Object ret = m.Invoke(o, new Object[] { 42 });
Console.WriteLine("MetodoDeEjemplo retorno: {0}.", ret);

MethodInfo m2 = assem.GetType("Ejemplo2").GetMethod("OtroMetodo");
ret = m2.Invoke(o, new Object[] { "Este Texto" });
Console.WriteLine("OtroMetodo retorno: {0}.", ret);

Console.WriteLine("\nPunto de entrada del Assembly:");
Console.WriteLine(assem.EntryPoint);
}
}

Ejecute el codigo y vera que nos muestra lo siguiente:

El nombre del assembly
El metodo que hemos ejecutado y el valor que retorna el mismo
El punto de entrada del assembly

No hay comentarios: