English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Reflexão (Reflection) do C#

A reflexão é a capacidade de um programa acessar, detectar e modificar seu próprio estado ou comportamento.

As assemblys contêm módulos, e os módulos contêm tipos, e os tipos contêm membros. A reflexão fornece objetos encapsulados para assemblies, módulos e tipos.

Você pode usar a reflexão para criar dinamicamente exemplos de tipos, vincular tipos a objetos existentes ou obter tipos de objetos existentes. Em seguida, você pode chamar métodos do tipo ou acessar seus campos e propriedades.

Vantagens e desvantagens

Vantagens:

  • 1、A reflexão aumenta a flexibilidade e a expansibilidade do programa.

  • 2、Reduz a耦合 e melhora a capacidade de adaptação.

  • 3、Permite que o programa crie e controle objetos de qualquer classe, sem precisar prévia e codificação rígida da classe alvo.

Desvantagens:

  • 1、Problemas de desempenho: o uso da reflexão é basicamente uma operação de interpretação, que é muito mais lenta do que o código direto ao acessar campos e métodos. Portanto, o mecanismo de reflexão é principalmente aplicado em sistemas de frameworks que exigem alta flexibilidade e escalabilidade, e não é recomendado para programas comuns.

  • 2、A utilização da reflexão pode obscurecer a lógica interna do programa; os programadores desejam ver a lógica do programa no código-fonte, mas a reflexão desvia da técnica do código-fonte, o que pode levar a problemas de manutenção, e o código de reflexão é mais complexo do que o código direto correspondente.

Os usos da reflexão (Reflection)

A reflexão (Reflection) tem os seguintes usos:

  • Permite ver informações de características (attributes) no tempo de execução.

  • Permite examinar vários tipos na coleção e exemplificar esses tipos.

  • Permite a ligação atrasada de métodos e propriedades (properties).

  • Permite criar novos tipos no tempo de execução e executar algumas tarefas com esses tipos.

Verificar metadados

Já mencionamos em capítulos anteriores que a reflexão (Reflection) pode ser usada para verificar informações de características (attributes).

System.Reflection da classe MemberInfo O objeto precisa ser inicializado para descobrir as características relacionadas à classe. Para fazer isso, você pode definir um objeto da classe alvo, conforme abaixo:

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

O seguinte programa demonstra isso:

using System;
[AttributeUsage(AttributeTargets.All)]
public class HelpAttribute : System.Attribute
{
   public readonly string Url;
   public string Topic  // Topic é um parâmetro nomeado
   {
      obter
      {
         return topic;
      }
      definir
      {
         topic = value;
      }
   }
   public HelpAttribute(string url)  // url é um parâmetro posicional
   {
      this.Url = url;
   }
   private string topic;
}
[HelpAttribute("Informações sobre a classe 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();
      }
   }
}

Quando o código acima for compilado e executado, ele exibirá as características adicionadas à classe MyClass da característica personalizada:

HelpAttribute

exemplo online

Neste exemplo, utilizaremos o que foi criado no capítulo anterior DeBugInfo característica, e usa reflexão (Reflection) para ler Retângulo Metadados da classe.

using System;
using System.Reflection;
namespace BugFixApplication
{
   // Uma característica personalizada BugFix é atribuída à classe e seus membros
   [AttributeUsage(AttributeTargets.Classe |
   AttributeTargets.Construtor |
   AttributeTargets.Field |
   AttributeTargets.Método |
   AttributeTargets.Property,
   PermitirMúltiplos = true)]
   public class DeBugInfo : System.Attribute
   {
      private int númeroDoBug;
      private string desenvolvedor;
      private string últimaRevisão;
      public string mensagem;
      public DeBugInfo(int bg, string dev, string d)
      {
         this.númeroDoBug = bg;
         this.desenvolvedor = dev;
         this.últimaRevisão = d;
      }
      public int NúmeroDoBug
      {
         obter
         {
            retornar númeroDoBug;
         }
      }
      public string Desenvolvedor
      {
         obter
         {
            retornar desenvolvedor;
         }
      }
      public string ÚltimaRevisão
      {
         obter
         {
            retornar últimaRevisão;
         }
      }
      public string Mensagem
      {
         obter
         {
            retornar mensagem;
         }
         definir
         {
            mensagem = valor;
         }
      }
   }
   [DeBugInfo(45, "Zara Ali", "12/8/2012"
        Mensagem = "Tipo de retorno não coincide")]
   [DeBugInfo(49, "Nuha Ali", "10/10/2012"
        Mensagem = "Variável não usada")]
   class Rectangle
   {
      // Variáveis de membro
      protected double comprimento;
      protected double largura;
      public Rectangle(double l, double w)
      {
         comprimento = l;
         largura = w;
      }
      [DeBugInfo(55, "Zara Ali", "19/10/2012"
           Mensagem = "Tipo de retorno não coincide")]
      public double GetArea()}}
      {
         return length * width;
      }
      [DeBugInfo(56, "Zara Ali", "19/10/2012)
      public void Display()
      {
         Console.WriteLine("Comprimento: {0}", length);
         Console.WriteLine("Largura: {0}", width);
         Console.WriteLine("Área: {0}", GetArea());
      }
   }//fim da classe Rectangle  
   
   class ExecuteRectangle
   {
      static void Main(string[] args)
      {
         Rectangle r = new Rectangle(4.5, 7.5);
         r.Display();
         Type type = typeof(Rectangle);
         // Percorrendo as características da classe Rectangle
         foreach (Object attributes in type.GetCustomAttributes(false))
         {
            DeBugInfo dbi = (DeBugInfo)attributes;
            if (null != dbi)
            {
               Console.WriteLine("Número do Bug: {0}", dbi.BugNo);
               Console.WriteLine("Desenvolvedor: {0}", dbi.Developer);
               Console.WriteLine("Última Revisão: {0}",
                                        dbi.LastReview);
               Console.WriteLine("Observações: {0}", dbi.Message);
            }
         }
         
         // Percorrendo as características do método
         foreach (MethodInfo m in type.GetMethods())
         {
            foreach (Attribute a in m.GetCustomAttributes(true))
            {
               DeBugInfo dbi = (DeBugInfo)a;
               if (null != dbi)
               {
                  Console.WriteLine("Número do Bug: {0}, para Método: {1}",
                                                dbi.BugNo, m.Name);
                  Console.WriteLine("Desenvolvedor: {0}", dbi.Developer);
                  Console.WriteLine("Última Revisão: {0}",
                                                dbi.LastReview);
                  Console.WriteLine("Observações: {0}", dbi.Message);
               }
            }
         }
         Console.ReadLine();
      }
   }
}

Quando o código acima for compilado e executado, ele produzirá o seguinte resultado:

Comprimento: 4.5
Largura: 7.5
Área: 33.75
Número do Bug: 49
Desenvolvedor: Nuha Ali
Última Revisão: 10/10/2012
Observações: Variável não usada
Número do Bug: 45
Desenvolvedor: Zara Ali
Última Revisão: 12/8/2012
Observações: Descompatibilidade de tipo de retorno
Número do Bug: 55, para Método: GetArea
Desenvolvedor: Zara Ali
Última Revisão: 19/10/2012
Observações: Descompatibilidade de tipo de retorno
Número do Bug: 56, para Método: Display
Desenvolvedor: Zara Ali
Última Revisão: 19/10/2012
Observações: