C# Reflexión (Reflection)

La reflexión se refiere a la capacidad de un programa para acceder, detectar y modificar su propio estado o comportamiento.

Los ensamblados contienen módulos, los módulos contienen tipos y los tipos contienen miembros. La reflexión proporciona objetos que encapsulan ensamblados, módulos y tipos.

Puede utilizar la reflexión para crear dinámicamente instancias de un tipo, enlazar el tipo a un objeto existente u obtener el tipo de un objeto existente. Luego, puede invocar los métodos del tipo o acceder a sus campos y propiedades.

Ventajas y desventajas

Ventajas:

  • 1. La reflexión mejora la flexibilidad y la extensibilidad del programa.
  • 2. Reduce el acoplamiento y mejora la capacidad de adaptación.
  • 3. Permite que el programa cree y controle objetos de cualquier clase sin necesidad de codificar de antemano la clase de destino.

Desventajas:

  • 1. Problemas de rendimiento: el uso de la reflexión es básicamente una operación de interpretación que, para el acceso a campos y métodos, es mucho más lenta que el código directo. Por lo tanto, el mecanismo de reflexión se aplica principalmente en marcos de sistema que requieren alta flexibilidad y extensibilidad; no se recomienda su uso en programas comunes.
  • 2. El uso de la reflexión puede oscurecer la lógica interna del programa; los programadores esperan ver la lógica del programa en el código fuente, pero la reflexión evade las técnicas del código fuente, lo que genera problemas de mantenimiento. El código de reflexión es más complejo que el código directo correspondiente.

Usos de la reflexión (Reflection)

La reflexión (Reflection) tiene los siguientes usos:

  • Permite ver información de atributos (attribute) en tiempo de ejecución.
  • Permite examinar varios tipos en una colección e instanciar estos tipos.
  • Permite métodos y propiedades (property) con enlace retardado.
  • Permite crear nuevos tipos en tiempo de ejecución y luego utilizar estos tipos para realizar algunas tareas.

Ver metadatos

Ya hemos mencionado en los capítulos anteriores que se puede utilizar la reflexión (Reflection) para ver información de atributos (attribute).

System.ReflectionDe la claseMemberInfoEl objeto necesita ser inicializado para descubrir los atributos (attribute) relacionados con la clase. Para lograr esto, puede definir un objeto de la clase de destino, como se muestra a continuación:

System.Reflection.MemberInfo info = typeof(MyClass);

El siguiente programa demuestra esto:

Ejemplo

using System;

[AttributeUsage(AttributeTargets.All)]
public class HelpAttribute : System.Attribute
{
   public readonly string Url;

   public string Topic  // Topic es un parámetro con nombre (named)
   {
      get
      {
         return topic;
      }
      set
      {

         topic = value;
      }
   }

   public HelpAttribute(string url)  // url es un parámetro posicional (positional)
   {
      this.Url = url;
   }

   private string topic;
}
[HelpAttribute("Information on the class MyClass")]
class MyClass
{
}

namespace AttributeAppl
{
   class Program
   {
      static void Main(string[] args)
      {
         System.Reflection.MemberInfo info = typeof(MyClass);
         object[] attributes = info.GetCustomAttributes(true);
         for (int i = 0; i < attributes.Length; i++)
         {
            System.Console.WriteLine(attributes[i]);
         }
         Console.ReadKey();

      }
   }
}

Cuando el código anterior se compila y ejecuta, mostrará los atributos personalizados adjuntos a laMyClassclase:

HelpAttribute

Ejemplo

En este ejemplo, utilizaremos los atributos creados en el capítulo anteriorDeBugInfoy usaremos la reflexión (Reflection) para leerRectanglelos metadatos de la clase.

Ejemplo

using System;
using System.Reflection;
namespace BugFixApplication
{
   // Un atributo personalizado BugFix se asigna a la clase y a sus miembros
   [AttributeUsage(AttributeTargets.Class |
   AttributeTargets.Constructor |
   AttributeTargets.Field |
   AttributeTargets.Method |
   AttributeTargets.Property,
   AllowMultiple = true)]

   public class DeBugInfo : System.Attribute
   {
      private int bugNo;
      private string developer;
      private string lastReview;
      public string message;

      public DeBugInfo(int bg, string dev, string d)
      {
         this.bugNo = bg;
         this.developer = dev;
         this.lastReview = d;
      }

      public int BugNo
      {
         get
         {
            return bugNo;
         }
      }
      public string Developer
      {
         get
         {
            return developer;
         }
      }
      public string LastReview
      {
         get
         {
            return lastReview;
         }
      }
      public string Message
      {
         get
         {
            return message;
         }
         set
         {
            message = value;
         }
      }
   }
   [DeBugInfo(45, "Zara Ali", "12/8/2012",
        Message = "Return type mismatch")]
   [DeBugInfo(49, "Nuha Ali", "10/10/2012",
        Message = "Unused variable")]
   class Rectangle
   {
      // Variables miembro
      protected double length;
      protected double width;
      public Rectangle(double l, double w)
      {
         length = l;
         width = w;
      }
      [DeBugInfo(55, "Zara Ali", "19/10/2012",
           Message = "Return type mismatch")]
      public double GetArea()
      {
         return length * width;
      }
      [DeBugInfo(56, "Zara Ali", "19/10/2012")]
      public void Display()
      {
         Console.WriteLine("Length: {0}", length);
         Console.WriteLine("Width: {0}", width);
         Console.WriteLine("Area: {0}", GetArea());
      }
   }//end class Rectangle  
   
   class ExecuteRectangle
   {
      static void Main(string[] args)
      {
         Rectangle r = new Rectangle(4.5, 7.5);
         r.Display();
         Type type = typeof(Rectangle);
         // Recorrer los atributos de la clase Rectangle
         foreach (Object attributes in type.GetCustomAttributes(false))
         {
            DeBugInfo dbi = (DeBugInfo)attributes;
            if (null != dbi)
            {
               Console.WriteLine("Bug no: {0}", dbi.BugNo);
               Console.WriteLine("Developer: {0}", dbi.Developer);
               Console.WriteLine("Last Reviewed: {0}",
                                        dbi.LastReview);
               Console.WriteLine("Remarks: {0}", dbi.Message);
            }
         }
         
         // Recorrer los atributos de los métodos
         foreach (MethodInfo m in type.GetMethods())
         {
            foreach (Attribute a in m.GetCustomAttributes(true))
            {
               DeBugInfo dbi = (DeBugInfo)a;
               if (null != dbi)
               {
                  Console.WriteLine("Bug no: {0}, for Method: {1}",
                                                dbi.BugNo, m.Name);
                  Console.WriteLine("Developer: {0}", dbi.Developer);
                  Console.WriteLine("Last Reviewed: {0}",
                                                dbi.LastReview);
                  Console.WriteLine("Remarks: {0}", dbi.Message);
               }
            }
         }
         Console.ReadLine();
      }
   }
}

Cuando el código anterior se compila y ejecuta, produce los siguientes resultados:

Length: 4.5
Width: 7.5
Area: 33.75
Bug No: 49
Developer: Nuha Ali
Last Reviewed: 10/10/2012
Remarks: Unused variable
Bug No: 45
Developer: Zara Ali
Last Reviewed: 12/8/2012
Remarks: Return type mismatch
Bug No: 55, for Method: GetArea
Developer: Zara Ali
Last Reviewed: 19/10/2012
Remarks: Return type mismatch
Bug No: 56, for Method: Display
Developer: Zara Ali
Last Reviewed: 19/10/2012
Remarks: 
Otras extensiones