Reflexión en C#: Descubrimiento de tipos en tiempo de ejecución y programación dinámica
Los objetos de Reflexión (Reflection) se usan para obtener información de tipo en tiempo de ejecución. Las clases que dan acceso a los metadatos de un programa en ejecución están en el espacio de nombres System.Reflection.
El namespace System.Reflection contiene clases que permiten obtener información sobre la aplicación y agregar dinámicamente tipos, valores y objetos a la aplicación.
Aplicaciones de la reflexión
- Permite ver información de atributos en tiempo de ejecución.
- Permite examinar varios tipos en un ensamblado e instanciar estos tipos.
- Permite enlace tardío (late binding) a métodos y propiedades.
- Permite crear nuevos tipos en tiempo de ejecución y realizar tareas con ellos.
Visualización de metadatos
Usando reflexión puede ver la información de atributos. El objeto MemberInfo de la clase System.Reflection necesita inicializarse para descubrir los atributos asociados con una clase.
System.Reflection.MemberInfo info = typeof(MiClase);
Ejemplo:
using System;
[AttributeUsage(AttributeTargets.All)]
public class HelpAttribute : System.Attribute {
public readonly string Url;
public string Topic {
get { return topic; }
set { topic = value; }
}
public HelpAttribute(string url) { this.Url = url; }
private string topic;
}
[HelpAttribute("Información sobre la clase MiClase")]
class MiClase { }
namespace AplicaciónAtributo {
class Program {
static void Main(string[] args) {
System.Reflection.MemberInfo info = typeof(MiClase);
object[] atributos = info.GetCustomAttributes(true);
for (int i = 0; i < atributos.Length; i++) {
System.Console.WriteLine(atributos[i]);
}
Console.ReadKey();
}
}
}
Resultado:
HelpAttribute
Ejemplo: Uso del atributo DeBugInfo con reflexión
Usamos el atributo DeBugInfo creado en el capítulo anterior y reflexión para leer metadatos en la clase Rectángulo.
using System;
using System.Reflection;
namespace AplicaciónCorrecciónBugs {
[AttributeUsage(
AttributeTargets.Class | AttributeTargets.Constructor |
AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Property,
AllowMultiple = true)]
public class DeBugInfo : System.Attribute {
private int bugNo;
private string desarrollador;
private string últimaRevisión;
public string mensaje;
public DeBugInfo(int bg, string dev, string d) {
this.bugNo = bg;
this.desarrollador = dev;
this.últimaRevisión = d;
}
public int BugNo { get { return bugNo; } }
public string Desarrollador { get { return desarrollador; } }
public string ÚltimaRevisión { get { return últimaRevisión; } }
public string Mensaje { get { return mensaje; } set { mensaje = value; } }
}
[DeBugInfo(45, "Zara Ali", "12/8/2012", Message = "Return type mismatch")]
[DeBugInfo(49, "Nuha Ali", "10/10/2012", Message = "Unused variable")]
class Rectángulo {
protected double longitud;
protected double ancho;
public Rectángulo(double l, double w) {
longitud = l; ancho = w;
}
[DeBugInfo(55, "Zara Ali", "19/10/2012", Message = "Return type mismatch")]
public double GetÁrea() { return longitud * ancho; }
[DeBugInfo(56, "Zara Ali", "19/10/2012")]
public void Mostrar() {
Console.WriteLine("Longitud: {0}", longitud);
Console.WriteLine("Ancho: {0}", ancho);
Console.WriteLine("Área: {0}", GetÁrea());
}
}
class EjecutarRectángulo {
static void Main(string[] args) {
Rectángulo r = new Rectángulo(4.5, 7.5);
r.Mostrar();
Type tipo = typeof(Rectángulo);
// Iterar atributos de la clase
foreach (Object atributos in tipo.GetCustomAttributes(false)) {
DeBugInfo dbi = (DeBugInfo)atributos;
if (dbi != null) {
Console.WriteLine("Bug No: {0}", dbi.BugNo);
Console.WriteLine("Desarrollador: {0}", dbi.Desarrollador);
Console.WriteLine("Última revisión: {0}", dbi.ÚltimaRevisión);
Console.WriteLine("Observaciones: {0}", dbi.Mensaje);
}
}
// Iterar atributos de métodos
foreach (MethodInfo m in tipo.GetMethods()) {
foreach (Attribute a in m.GetCustomAttributes(true)) {
DeBugInfo dbi = (DeBugInfo)a;
if (dbi != null) {
Console.WriteLine("Bug No: {0}, para Método: {1}", dbi.BugNo, m.Name);
Console.WriteLine("Desarrollador: {0}", dbi.Desarrollador);
Console.WriteLine("Última revisión: {0}", dbi.ÚltimaRevisión);
Console.WriteLine("Observaciones: {0}", dbi.Mensaje);
}
}
}
Console.ReadLine();
}
}
}
Resultado:
Longitud: 4.5
Ancho: 7.5
Área: 33.75
Bug No: 49
Desarrollador: Nuha Ali
Última revisión: 10/10/2012
Observaciones: Unused variable
Bug No: 45
Desarrollador: Zara Ali
Última revisión: 12/8/2012
Observaciones: Return type mismatch
Bug No: 55, para Método: GetÁrea
Desarrollador: Zara Ali
Última revisión: 19/10/2012
Observaciones: Return type mismatch
Bug No: 56, para Método: Mostrar
Desarrollador: Zara Ali
Última revisión: 19/10/2012
Observaciones:
Lenguaje C
- C# Hola Mundo – Construyendo su primera aplicación en C#
- Entendiendo palabras clave e identificadores en C#: Reglas, listas y mejores prácticas
- Domine variables y tipos de datos primitivos en C#: Guía completa
- Operadores en C# – Guía completa de operadores en C#
- Dominando operadores bit a bit y de desplazamiento en C#: Guía completa
- Fundamentos de C#: Entrada y salida esenciales
- Expresiones, sentencias y bloques en C#: Guía completa con ejemplos prácticos
- Dominando los comentarios en C#: Tipos, mejores prácticas y documentación XML
- Sentencia break en C#: Cómo y cuándo usarla
- Dominando la sentencia continue en C#: Cómo saltar iteraciones de bucles eficazmente
- Dominando arrays en C#: Declaración, inicialización y operaciones