sábado, 7 de junio de 2014

Receta No. 3-16 en C#: Invocar un Miembro de un Tipo con Reflection

Tabla de Contenido

0. Introducción
1. Problema
2. Solución
3. Discusión de la Solución
3.1 Método InvokeMember
3.2 Método Invoke
4. Práctica: Código Fuente C#
5. Conclusiones
6. Glosario
7. Literatura & Enlaces

0. Introducción

Ahora que tenemos el conocimiento y práctica suficientes y necesarios sobre cómo obtener los miembros de un tipo (Uso Programático para Investigar y Descubrir los Miembros de un Tipo), es momento de entender cómo podemos invocar el miembro de un tipo usando la técnica .NET Reflection.

1. Problema

Necesitamos conocer la forma en que podemos invocar los miembros de un tipo usando .NET Reflection.

2. Solución

En .NET Framework existen dos formas disponibles para invocar los miembros de los que dispone un tipo:
  1. Método InvokeMember de Type, o 
  2. Método Invoke de la clase MemberInfo, o cualquiera que derive de esta:
    1. MethodInfo
    2. PropertyInfo
    3. ConstructorInfo

3. Discusión de la Solución

Conozcamos la forma programática de invocar los miembros de un tipo usando las dos formas mencionadas en la sección 2.

3.1 Método InvokeMember

El método InvokeMember [3] posee las siguientes versiones de firmas sobrecargadas:
Lista sobrecargada de Type.InvokeMember
Figura 1. Lista sobrecargada de Type.InvokeMember [3].
Para ejemplificar su uso vamos utilizar la primera versión, es decir, la que posee la firma:

public Object InvokeMember(string name, BingingFlags invokeAttr, Binder binder, Object target, Object[] args)

Descripción puntual:
  • Parámetro name: cadena de caracteres con el nombre del miembro (constructor, método, propiedad, etc.)
  • Parámetro invokeAttr: determina la forma en que se realizará la búsqueda a través de reflection. Consiste en la especificación bitwise OR de la enumeración BindingFlags [5].
  • Parámetro binder: especificador de propiedades o características que ayudan a resolver el miembro sobrecargado a invocar, por ejemplo.
  • Parámetro target: objeto sobre el que se invocará el miembro. (Si null es para señalar que se trata de un constructor.)
  • Parámetro args: arreglo con los argumentos a pasar al miembro a invocar.
  • Tipo de retorno Object: Representa el valor de retorno del miembro que se ha invocado.
Ejemplo de uso:

Archivo de código fuente UsoInvokeMember.cs [enlace alternativo]:
En las línea 7-36 declaramos la clase ClaseDemo con varios miembros (un campo, un constructor, una propiedad, y el método ToString sobrescrito). En la línea 43 creamos la representación Type para la clase ClaseDemo. Creamos un arreglo de elementos object con un sólo elemento (valor 8) en la línea 46. Con la línea 50 probamos el valor de args[0] antes de invocar el constructor de ClaseDemo


Continuando, entre las líneas 53-56, invocamos al método InvokeMember pasando los siguientes argumentos:
  • Nombre de miembro null: para señalar que vamos a invocar un constructor (ClaseDemo (ref int x))
  • Valores de la enumeración BindingFlags:
    • DeclaredOnly: especifica que sólo buscará entre los miembros declarados en el tipo especificado. Omitirá la búsqueda de miembros heredados.
    • NonPublic: especifica que los miembros ~public serán incluidos en la búsqueda.
    • Public: especifica que los miembros public serán incluidos en la búsqueda.
    • Instance: especifica que los miembros de instancia serán incluidos en la búsqueda.
    • CreateInstance: especifica que a través de reflection se debe crear la instancia del tipo especificado.
  • Binder null: uso de los atributos por defecto para búsqueda de miembros sobrecargados.
  • Objetivo null: indica que se va a crear una instancia del tipo especificado a través del invoca al método InvokeMember.
  • Argumentos args: los argumentos con los que se creará la instancia de ClaseDemo.
En la línea 58 se muestra en la salida estándar el tipo concreto devuelto por las líneas comentadas anteriormente. Sobre la ínea 59, mostramos el valor de args[0]; el cual fue pasado como referencia al constructor (línea 26) de ClaseDemo.


De forma análoga, aunque con evidente diferencia en la configuración de la invocación del método InvokeMember, se establece y obtiene valores para los miembros en el resto de código fuente:
  • campo (lineas 65-75),
  • ToString (líneas 79-82), y 
  • Propiedad (líneas 90-9)
> Prueba de ejecución.

Resultado:
Prueba de ejecución con el uso del método InvokeMember
Figura 2. Prueba de ejecución con el uso del método InvokeMember.

3.2 Método Invoke

Para mostrar las capacidades del método Invoke, utilizaremos la implementación de este sobre la clase ConstructorInfo [6] que se haya en [7]. Empero, recurriremos a la versión sobrecargada con firma [8]:

public Object Invoke(Object[] parameters)

Descripción puntual:
  • Parámetro Object[]: arreglo con los parámetros del constructor.
  • Tipo de retorno Object: retorna instancia del tipo especificado.
Ejemplo de uso:

Archivo de código fuente CreacionStringBuilder.cs [enlace alternativo]:
En la línea 25 obtenemos la representación Type de StringBuilder [11] con el uso del operador typeof. Con la sentencia 

Type[] argsTipos = new Type[] { typeof (String), typeof(Int32)};


en la línea 29 especificamos la lista de los tipos de los parámetros para un constructor de StringBuilder ([12]). La variable argsTipos la pasamos como argumento al método GetConstructor (línea 32) para obtener la información del constructor sobre una instancia ConstructorInfo. Los argumentos para la firma del constructor recién creado los especificamos en un arreglo object en la línea 35. Finalmente, ya podemos crear la instancia invocando al método Invoke en la sentencia de la línea 38. El código cliente (líneas 9-20) comprende el uso de una instancia de StringBuilder.


Compilación:


  1. csc /target.exe CreacionStringBuilder.cs

Prueba de ejecución.

Resultado:

Blog xCSw

4. Práctica: Código Fuente C#

Con este ejemplo vamos a recapitular (con el fin de afianzar el conocimiento adquirido) el uso del método InvokeMethod y el método Invoke:

Archivo de código fuente ReflectionConInvokeMethod.cs [enlace alternativo]:
Compilación:


  1. csc /target.exe ReflectionConInvokeMethod.cs

Ejecución:


  1. .\ReflectionConInvokeMethod.exe

Resultado:
Valores de `param1`: Blog xCSw; `param2`: 235; `param3`: #
Valores de `param1`: Blog xCSw; `param2`: 235; `param3`: #

5. Conclusiones

Utilizamos los artefactos (métodos) de las clases ConstructorInfo, MethodInfo, y Type para demostrar el uso de los métodos Invoke y InvokeMember para demostrar el proceso de invocación de miembros de tipo en tiempo de ejecución usando .NET Reflection. En la siguiente receta (penúltima de esta serie de dominios de aplicación, meta-datos, y reflection) conoceremos el proceso de invocar de forma dinámica el miembro de un tipo.

6. Glosario

  • Invocar
  • Invoke
  • InvokeMember
  • Miembro
  • Reflection

Literatura & Enlaces

[1]: Visual C# 2010 Recipes by Allen Jones and Adam Freeman. Copyright 2010 Allen Jones and Adam Freeman, 978-1-4302-2525-6.
[2]: Type.InvokeMember Method (System) - http://msdn.microsoft.com/en-us/library/system.type.invokemember(v=vs.110).aspx
[3]: Type.InvokeMember Method (System) - http://msdn.microsoft.com/en-us/library/system.type.invokemember(v=vs.110).aspx
[4]: Type.InvokeMember Method (String, BindingFlags, Binder, Object, Object[]) (System) - http://msdn.microsoft.com/en-us/library/66btctbe(v=vs.110).aspx
[5]: BindingFlags Enumeration (System.Reflection) - http://msdn.microsoft.com/en-us/library/system.reflection.bindingflags(v=vs.110).aspx
[6]: ConstructorInfo Class (System.Reflection) - http://msdn.microsoft.com/en-us/library/system.reflection.constructorinfo(v=vs.110).aspx
[7]: ConstructorInfo.Invoke Method (System.Reflection) - http://msdn.microsoft.com/en-us/library/system.reflection.constructorinfo.invoke(v=vs.110).aspx
[8]: ConstructorInfo.Invoke Method (Object[]) (System.Reflection) - http://msdn.microsoft.com/en-us/library/6ycw1y17(v=vs.110).aspx


M

No hay comentarios:

Publicar un comentario

Envíe sus comentarios, dudas, sugerencias, críticas. Gracias.