Tabla de Contenido
0. Introducción1. Problema
2. Solución
3. Discusión de la Solución Conclusiones
4. Práctica: Código Fuente C#
4.1 Instanciar un objeto StringBuilder
4.2 Factoría de plugins
5. Conclusiones
6. Glosario
7. Literatura & Enlaces
0. Introducción
Esta doceava receta nos enseñará el proceso requerido para instanciar objetos en tiempo de ejecución usando una técnica que es conocida como Reflection. A través de reflection podemos conocer la meta-información asociada a un tipo, de un assembly, etc., esto será útil nuestra aplicación se haya en ejecución. Recurriremos a varios de los artefactos localizados en los namespace System y System.Reflection para lograr nuestro objetivo: crear una instancia de un tipo de los assemblies de Microsoft .NET Framework y los de código personalizado del usuario.
1. Problema
Queremos acercarnos al uso de reflection en nuestros desarrollos. Por eso hemos pedido al equipo de formación que nos indique el proceso necesario para crear instancias de un tipo de objeto en tiempo de ejecución.
2. Solución
El equipo del departamento de formación de Ad Infinitum Systems. Nos ha entregado un esquema abstracto de trabajo sobre C# para empezar a investigar y realizar primeras pruebas con el concepto de reflection. Aquí está:
- Obtención de la representación Type de un objeto.
- Invocación del constructor que nos interese a través del método GetConstructor. para la obtención de una instancia de ConstructorInfo (N:System.Reflection).
- Invocación del método ConstructorInfo.Invoke.
3. Discusión de la solución
3.1 Introducción a Reflection
De acuerdo con [4], reflection es una técnica que consiste en la investigación o consulta de información de un tipo, assembly, módulo, &c., en tiempo ejecución. Esto nos abre la posibilidad de manipular los miembros (métodos, propiedades, constructores, eventos, etc.) de un tipo de objeto con técnicas conocidas de programación.
Con el siguiente ejemplo queda mejor ilustrado el concepto de reflection:
En la línea 4 creamos una clase concreta Calculadora y creamos el método Sumar (líneas 8-11) en su cuerpo de declaración. Desde código cliente (líneas 16-34), creamos un instancia de esa Calculadora; luego a través del método heredado de Object, GetType, obtenemos la representación Type [5] de ese objeto. A continuación, solicitamos la obtención del método -infoTipo.GetMethod("Sumar")-, y lo invocamos con el conjunto de argumentos especificados en el arreglo object infoMetodo.Invoke(calc, args) (línea 33).
> Prueba de ejecución.
Resultado:
Reflection: MethodInfo
Nombre tipo: Recetas.Cap03.Calculadora Retorno: 10
3.2 Creación objetos con reflection
A partir de lo que comprendimos en la sección anterior, vamos a extender los pasos requeridos para la creación de una instancia de un objeto en tiempo de ejecución utilizando la técnica reflection. Estos son los pasos:
Paso 1: Obtención de la representación Type del objeto
En la Figura 1 se ilustra (a modo de resumen) los métodos de obtención de la representación Type para cualquier tipo de objeto.
Figura 1. Métodos de obtención representación Type. |
En la receta 3.10 (Obtención de Información de Tipos (Reflection)) podrán encontrar más detalle acerca de este proceso.
Paso 2: Invocar método GetConstructor
El método GetConstructor posee una lista de versiones sobrecargadas [7]. Utilizaremos, para ejemplificar, la versión que recibe un arreglo de objetos Type como argumento. Esta es su firma [8]:
public ConstructorInfo GetConstructor(Type[] types)
Este es un ejemplo (recuperado y adaptado de [8]):
Archivo UsoTypeGetConstructor.cs [enlace alternativo]:
En línea 15 obtenemos la representación Type para la clase UsoTypeGetConstructor; más adelante, en la línea 18 obtenemos una instancia de ConstructorInfo que hace referencia al constructor de UsoTypeGetConstructor con un parámetro int. Al método GetConstructor se le pasa el arreglo de elementos Type con la representación Type para int. En caso que la invocación
tipo.GetConstructor(new Type[] {typeof(int)});
retorne un valor diferente a null, se ejecutará la sentencia de la línea 22.
Resultado:
Constructor con firma que contiene un parámetro `int`: Void .ctor(Int32)
Paso 3: Invocación del método Invoke de ConstructorInfo
El método Invoke [9] se encarga de invocar el constructor a una variable ConstructorInfo. La versión sobrecargada [10] permite especificar los argumentos para el constructor referenciado por una instancia de ConstructorInfo. Firma de este último:
public Object Invoke(Object[] parameters)
En la línea 22 invocamos al constructor con la lista de argumentos especificada con:
new object[] {13}
para el argumento del método Invoke. Hacemos el casting para obtener la instancia del tipo correspondiente:
(UsoTypeGetConstructor)
Resultado:
Blog xCSw
3.3 Aplicaciones de reflection
En [1] enuncian una aplicación de la técnica reflection:Reflection functionality is commonly used to implement factories in which you use reflection to instantiate concrete classes that either extend a common base class or implement a common interface. Often, both an interface and a common base class are used. The abstract base class implements the interface and any common functionality, and then each concrete implementatation extends the base class.
En el segundo ejemplo de la sección práctica crearemos una aplicación con esta característica.
4. Práctica: Código Fuente C#
4.1 Instanciar un objeto StringBuilder
En este primer ejemplo vamos a utilizar reflection para crear un objeto StringBuilder.
Archivo 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:
- csc /target.exe CreacionStringBuilder.cs
> Prueba de ejecución.
Resultado:
Blog xCSw
4.2 Factoría con reflection
El siguiente ejemplo es una adaptación del hallado en [1], el cual consiste en la creación de una factoría (creación de instancias) de objetos IPlugin.
Archivo de código fuente Factoria.cs [enlace alternativo]:
Compilación:
- csc /target.exe Factoria.cs
Ejecución:
- .\Factoria.exe
Resultado:
Figura 2. Resultado ejecución ejemplo de factoría de plugins. |
5. Conclusiones
La preparación de esta receta en C# nos ha enseñado los básicos para la creación de un objeto utilizando la técnica reflection. Esto es de bastante utilidad para crear objetos en tiempo de ejecución. También podemos manipular los tipos pertenecientes a un assembly y crear instancias según sea necesario (lo aprendimos con los ejemplos presentados en la sección 4).
6. Glosario
- Assembly
- Constructor
- ctor
- Factoría
- Instancia
- Objeto
- Plugins
- Reflection
7. 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]: Reflection in C# Tutorial - CodeProject - http://www.codeproject.com/Articles/17269/Reflection-in-C-Tutorial
[3]: Reflection (C# and Visual Basic) - http://msdn.microsoft.com/en-us/library/ms173183.aspx
[4]: Reflection in .NET - CodeProject - http://www.codeproject.com/Articles/55710/Reflection-in-NET
[5]: Type Class (System) - http://msdn.microsoft.com/en-us/library/system.type(v=vs.110).aspx
[6]: Receta No. 3-10 en C#: Obtención de Información de Tipos (Reflection) - http://ortizol.blogspot.com/2014/06/receta-no-3-10-en-csharp-obtencion-de-informacion-de-tipos-reflection.html
[7]: Type.GetConstructor Method (System) - http://msdn.microsoft.com/en-us/library/System.Type.GetConstructor(v=vs.110).aspx
[8]: Type.GetConstructor Method (Type[]) (System) - http://msdn.microsoft.com/en-us/library/h93ya84h(v=vs.110).aspx
[9]: ConstructorInfo.Invoke Method (System.Reflection) - http://msdn.microsoft.com/en-us/library/system.reflection.constructorinfo.invoke(v=vs.110).aspx
[10]: ConstructorInfo.Invoke Method (Object[]) (System.Reflection) - http://msdn.microsoft.com/en-us/library/6ycw1y17(v=vs.110).aspx
[11]: StringBuilder Class (System.Text) - http://msdn.microsoft.com/en-us/library/system.text.stringbuilder(v=vs.110).aspx
[12]: StringBuilder Constructor (String, Int32) (System.Text) - http://msdn.microsoft.com/en-us/library/zb91weab(v=vs.110).aspx
M
No hay comentarios:
Publicar un comentario
Envíe sus comentarios, dudas, sugerencias, críticas. Gracias.