[Tutorial] Introducción a System.Reflection

Iniciado por [D4N93R], 2 Junio 2010, 17:50 PM

0 Miembros y 1 Visitante están viendo este tema.

[D4N93R]

Introducción a System.Reflection

Reflection es la habilidad que tiene un código para revisar su propia estructura, es decir, podemos revisar la metadata que está en el assembly (en el caso de .net) y manipularla a nuestro antojo.

Con Reflection podemos encontrar cuarquier detalle sobre un objecto, assembly, propiedad, además de poder invocar métodos y obtener o establecer valores de una propiedad, todo ésto en tiempo de ejecución!

Esta habilidad nos da poder en nuestro código pero como todo,  hay que saber utilizarlo en el momento preciso y no abusar sobre el uso de Reflection ya que nuestro código podría verse afectado por pérdidas de performance.

Se preguntarán dónde y cuándo hay que utilizar Reflection, pues es algo que tienen que saber utilizar cuando lo necesiten, hay situaciones como formularios que requieren un diseño dinámico según el tipo que se pase en X parámetro, y en ese momento se preguntarán: "¿Escribo el formulario a hardcode, o utilizo reflection?", éste es uno de los casos más utilizados, también pódemos usarlo para serializar objectos de forma personalizada, etc.

¿Cómo comienzo a utilizar reflection?

Hay dos formas de comenzar: La primera es usando typeof() y la segunda es utilizando el método GetType() que todos los objectos tienen. Cualquiera de las dos formas que se usen retornan un objeto tipo Type, ese type es el que nos otorga la información de ese tipo.

Entre los principales métodos de Type tenemos:


  • GetField() Obtiene el campo según el nombre.
  • GetMethod() Obtiene un método, y si éste tiene sobre cargas, al igual que el constructor, hay que pasarle el tipo correspondiente de la sobre carga.
  • GetProperty() Obtiene la propiedad según el nombre.

Nota: aparte de los métodos anteriores existen los mismos en plural, es decir que en vez de obtener un miembro, obtienes un arreglo con los resultados según los parámetros que le indiques. Ejm: GetProperty() tienes:  GetProperties() el cual  puedes llamar sin parámetros para obtener un PropertyInfo[] con todas las propiedades.

Un punto muy importante es que en todo ésto, aunque hayamos sacado toda ésta información a partir de una instancia, Reflection se basa en metadata, es decir todo lo que exploramos y manipulamos, lo hacemos sin la instancia inicial, es por eso que cuando se vaya a invocar un método, a establecer valores en campos o propiedades, etc, nos pidan la instancia a la cual queremos realizar ese trabajo.

[D4N93R]

Para todos los ejemplos usaremos la siguiente clase:

Código (csharp) [Seleccionar]


public class Person
{
     private string m_firstName;
     private string m_lastName;
     
     public string FirstName
     {
          get { return m_firstName; }
          set { m_firstName = value; }
      }

     public string LastName
     {
          get { return m_lastName; }
          set { m_lastName = value; }
      }

      public void Run()
      {   }
}


[D4N93R]

GetField() y GetFields()

GetField nos regresa un FieldInfo y GetFields nos retorna un arreglo de FieldInfo, el cual podemos iterar.

FieldInfo tiene dos métodos muy importantes que son: GetValue y SetValue. Con GetValue obtenemos el valor que está almacenado en la instancia que pasemos como parámetro. Y SetValue establecemos a la instancia que pasamos como primer parámetro el valor que pongamos como segundo parámetro.

Ejemplo:

Código (csharp) [Seleccionar]
Person p = new Person();

Type t = p.GetType();

FieldInfo fInfo = t.GetField("m_firstName", BindingFlags.NonPublic | BindingFlags.Instance);

fInfo.SetValue(p,"Juan");



Bueno en primer lugar creamos una instancia de Person, luego obtenemos el tipo. De éste utilizamos GetField y el pasamos como parámetro el nombre del campo que queremos obtener, y también pasamos (BindingFlags.NonPublic | BindingFlags.Instance) como segundo parámetro, noten que es de tipo Flag, por lo que podemos pasar más de uno separado por el símbolo de pipe o tubería |. El BindingFlags.NonPublic es para decirle al método que el campo no es publico (obviamente). Y BindingFlags.Instance hace que el resultado sea de campos que se instancien,y no de campos estáticos. Luego de obtenerlo usamos el método SetValue al cual le pasa la instancia y el valor que se le quiere asignar al campo.



GetMethod() y GetMethods()

Al igual que GetFields, GetMethods nos retorna un arreglo pero de MethodInfo.

MethodInfo entre sus métodos podemos encontrar a GetParámeters y al Invoke, GetParámeters obtiene un arreglo con los parámetros, e Invoke que es el que va a hacer la llamada al método.

Para utilizarlo se hace de la siguiente manera:

Código (csharp) [Seleccionar]
Person p = new Person();

Type t = p.GetType();

MethodInfo mInfo = t.GetMethod("Run");

mInfo.Invoke(p, null);


Ejecutamos el GetMethod y le pasamos el nombre del método, nos retorna MethodInfo. Del MethodInfo ejecutamos el Invoke y le pasamos la instancia y como el método Run() no tiene parámetros le pasamos null, en caso contrario sería simplemente pasar un arreglo de object con los parámetros en el orden que aparecen en el método.

Nota: Invoke retorna object, así que si el método que están llamando tiene algún valor de retorno, solo sería cuestion de hacerle un cast: ejm:  

Código (csharp) [Seleccionar]
string nombre = (string) mInfo.Invoke(p, null);

GetProperty() y GetProperties()

Por último y no menos importante (de hecho es el que más he usado), están los GetProperty() que retorna un PropertyInfo y GetProperties() que retorna PropertyInfo[].

Los PropertyInfo funcionan parecido a los FieldInfo, tenemos GetValue y SetValue. Ahora un ejemplo:

Código (csharp) [Seleccionar]
Person p = new Person();

Type t = p.GetType();

PropertyInfo pInfo = t.GetProperty("FirstName");

string name = (string) pInfo.GetValue(p, new object[] {} );



Espero prontos extender más este tema.

raul338

:O queee lindooo!!! :) (?

Esta muy bueno (lo vi por encima, ni lo lei todavia pero...) me gusta el tema.


Lindo aporte

BlackZeroX


mmm creo que con esto puedo sustituir mi CallByName() del Basic tradicional... ya vere que tal xP.

Dulce Infierno Lunar!¡.
The Dark Shadow is my passion.

[D4N93R]

Gracias..

Si Reflection te resuelve mucho la vida en muchas ocasiones, todo tiene un costo, en este caso con Reflection se pierde un poco el rendimiento, pero es casi imperceptible, dependiendo de la situación obviamente.

Saludos!

Zzombi

no me quedo muy claro cuando se debe utilizar  :-\

[D4N93R]

En realidad no es uno de los namespaces más usados dentro del framework en aplicaciones cotidianas; pero es muy útil en algunos casos específicos. Te doy un ejemplo, yo una vez necesité hacer un SDK para un software de mi autoría, dentro del SDK cree ciertas interfaces y clases para la creación de addons para la aplicación en cuestión.

Bueno, Cómo logré que luego de programar un Addon poder cargalo en la aplicación? Pues utilizando Reflection puedes leer, examinar y ejecutar clases y ensamblados sin necesidad de tener tu el codigo, ni ninguna referencia directa.

Un saludo!

Zzombi

sería como un hook  :huh:

por lo que dices en el ejemplo, está bastante interesante  :D

[D4N93R]

No No un hook, eso es otra cosa. :) Reflection es un tema medio-avanzado, te recomiendo que leas algo más sencillo antes de adentrarte en estas clases.

Un saludo!