Story Transcript
Introducción Seguimos explorando aspectos del middleware y de la programación que resultarán relevantes a la hora de diseñar o construir middleware modernos. En esta práctica vamos a explorar el concepto de metadatos (anotación o atributo) y de reflexión.
Curso de Middleware. Práctica 6.
1 de 9
Anotaciones o Atributos Si recordamos nuestra práctica anterior, vemos que tuvimos que utilizar un atributo para la clase Fraccion. Pusimos una marca a la clase: using System; namespace Calculo { ...... [Serializable] public class Fraccion { ..... } }
Esta marca se denomina metadato, anotación (usando la nomenclatura de Java) o atributo (en C#). Es un concepto ya antiguo, pero que no ha sido utilizado ampliamente hasta hace unos años. Por ejemplo, Java lo incorpora a partir de la versión 5. Si hubiéramos utilizado Java, habríamos hecho algo parecido a:
...... @Serializable public class Fraccion { ..... }
Pero, ¿Qué es realmente un metadato? ¿Cómo se utiliza en general? Un metadato es una forma de añadir información adicional y descriptiva a nuestras clases (y otros elementos tales como variables, interface, etc.). Imaginemos que queremos definir y guardar la versión de una clase. Tenemos varias posibilidades. Una muy habitual es poner los comentarios correspondientes:
// Version: 1.20.111 public class Fraccion { ..... }
Curso de Middleware. Práctica 6.
2 de 9
Esa forma de incluir información en la clase es muy pobre. No podremos extraer información en tiempo de ejecución. Supongamos que queremos generar un error si la versión de la clase no es la correcta. Con esta solución sería inviable. Otra alternativa muy utilizada en lenguajes con menos recursos es definir una variable estática. Por ejemplo:
public class Fraccion { public static readonly string Version = “1.20.111”; ..... }
La principal desventaja de esta solución es que estamos insertando definiciones que no se corresponden con el concepto de “Fraccion”. Una fracción debe tener numerador y denominador, pero no es natural que tenga el concepto “Version”. Es algo que parece ir en contra de los conceptos de diseño orientado a objetos, ¿verdad?. Una marca o metadato es la mejor alternativa si el lenguaje dispone de tal característica. Es algo que está a medio camino de ambas soluciones, pero que aporta las ventajas de todas ellas. En nuestro caso, se podría hacer algo del estilo:
...... [Version(“1.20.11”)] public class Fraccion { ..... }
En esta práctica vamos a ver cómo definir atributos, cómo utilizarlos y cómo detectarlos en tiempo de ejecución.
Curso de Middleware. Práctica 6.
3 de 9
Definición de nuevos atributos Declarar un atributo en C# es simple: se utiliza la forma de una declaración de clase que hereda de System.Attribute y que se ha marcado con el atributo AttributeUsage, como se indica a continuación: using System; namespace Calculo { [AttributeUsage(AttributeTargets.All)] public class Version : System.Attribute { public string VersionNumber { get; set; } public Version(string ver) { this.VersionNumber = ver; } } }
Reutiliza la práctica anterior y añade una nueva clase en el proyecto “calculo”. Llama a este fichero “Version.cs” e inserta el código anterior. Ahora podrás anotar la clase fracción con esta nueva marca. Por ejemplo, prueba a realizar el siguiente cambio: [Version("1.2")] [Serializable] public class Fraccion { . . . }
Evidentemente, todo esto no serviría de mucho si no podemos consultar en tiempo de ejecución la información que hemos añadido. Para ello, vamos a dotar a nuestra calculadora de un método que imprime la versión de las objetos que le lleguen. Primero tenemos que añadir el siguiente código a la Calculadora (observa que hemos añadido también algunos “using” adicionales):
Curso de Middleware. Práctica 6.
4 de 9
using System; using System.Collections.Generic; using System.Reflection; namespace Calculo { public class Calculadora : System.MarshalByRefObject { private void LogVersion(object obj) { System.Reflection.MemberInfo info = obj.GetType(); foreach
(var
version
in
info.GetCustomAttributes(true)) { System.Console.WriteLine("La version es: " + version.VersionNumber); } } . . .
el resto de la calculadora
} }
y ahora podemos llamar a este nuevo método cuando sumemos fracciones. Por ejemplo;
public double SumaFraccion(Fraccion izq, Fraccion dch) { Console.WriteLine("Estoy sumando fraccion"); LogVersion(izq); return izq.Valor() + dch.Valor(); }
Si volvemos a ejecutar nuestra práctica deberíamos ver una traza (en el servidor) que nos dice que nuestra fracción tiene la versión 1.2.
Es un buen momento para que tu profesor os cuente conceptos de teoría. No avances en la práctica hasta asegurarte que has entendido correctamente los objetivos de la misma!!!!. Hemos visto el concepto de atributo o metadato. Repasemos algunos conceptos relevantes, y sobre todo veamos qué influencia podría tener en el Curso de Middleware. Práctica 6.
5 de 9
diseño de un middleware: •
Hemos visto que los atributos se pueden utilizar para definir la serialización de las clases. ¿Qué otros usos se te ocurren?
•
¿Cómo se definen las anotaciones propias (custom) en Java? ¿es posible? Intenta hacer algún ejemplo por tu cuenta o busca un ejemplo en internet.
•
Investiga el uso que hace Java de la anotación @override. ¿Por qué se utiliza una anotación? ¿Cómo lo hace C#? Esta forma de extender el lenguaje es interesante para la construcción de un middleware. ¿Sabrías explicar la razón?
•
¿Qué elementos del lenguaje (clase, método, interface, etc.) se pueden anotar? ¿Es igual en Java que en C#? ¿Qué pasa si un lenguaje no permite anotaciones?
•
¿Cómo introduce C# la información de versión, autor, etc. de un ensamblado (una librería o ejecutable)?.
•
Busca información sobre los sistemas de pruebas unitarias (en Visual Studio existe un sistema, pero también hay otros tales como Nunit). ¿Qué atributos existen? ¿Para qué sirve?. Os recomiendo que os separéis en grupos de trabajo para que cada grupo pueda explorar diferentes sistemas. Mirad también las alternativas en Java.
•
Mira en JavaEE las anotaciones más frecuentes. Haz lo mismo con las anotaciones que aparecen en Windows Communication Fundation (WCF) de C#. La conclusión es que los middleware utilizan en gran medida la capacidad de las anotaciones. En particular, es interesante el uso de las anotaciones en la definición de los web services.
•
Cuando un lenguaje no dispone de anotaciones o de reflexión. ¿Hay alternativas? ¿Cómo se construyen entonces los middleware?
Antes de pasar a la siguiente práctica es recomendable que se comente en grupo las principales consecuencias de lo que acabamos de ver.
Curso de Middleware. Práctica 6.
6 de 9
Ejercicios adicionales Os proponemos varios ejercicios que nos ayuden a entender el comportamiento de las anotaciones: 1. ¿Puedes decir si las anotaciones se heredan? Haz una hipótesis de trabajo y prueba mediante un ejemplo que tu hipótesis es correcta. Lo ideal es que varios de tus compañeros demuestren que se hereda y otros que no se hereda. ¿Qué resultado habéis obtenido? 2. Investiga ese mismo concepto (la herencia de las anotaciones) en Java. Comenta con tus compañeros si se comporta de la misma forma. 3. Crea una clase que herede de “Fraccion” e intenta serializarla. Como hemos visto anteriormente, la serialización debería fallar. ¿Por qué?. 4. Intenta hacer un ejemplo que reconstruya la definición de una clase a partir de la reflexión. La idea es construir un programa que pasando un objeto por parámetro escriba por pantalla los métodos que tiene, las variables que tiene, si procede de una herencia, etc. Este ejercicio es importante ya que nos permite entender no cómo los serializadores obtienen esa información. También nos permite conocer los mecanismos por los que un middleware puede publicar los servicios que ofrece.
Curso de Middleware. Práctica 6.
7 de 9
Resumen A lo largo de esta práctica hemos aprendido que los lenguajes modernos tienen capacidad para explorar (reflexión) y anotar (metadatos o anotaciones) el propio código. Tanto Java como C# ofrecen estas características. Hemos visto alguno de los usos que normalmente acompañan a estos conceptos. Y hemos estudiado cómo los middleware los utilizan para facilitar su utilización por parte del programador. En sucesivas lecciones veremos que todos estos conceptos son vitales en los middleware modernos.
Curso de Middleware. Práctica 6.
8 de 9
Conceptos introducidos En esta práctica hemos introducido/repasado los siguientes conceptos: • Atributo, metadato o anotación • Herencia en los metadatos • Reflexión • Tipos de metadatos. • Anotaciones usadas en la construccion de los Web Services
Curso de Middleware. Práctica 6.
9 de 9