Introdução: a magia da reflexão
Imagine que você está escrevendo um código que pode "olhar" para si mesmo. Não como em um espelho torto, mas como em um aparelho de raio-X — ver a estrutura, propriedades, métodos, até mesmo executá-los, sem saber o nome da classe em tempo de compilação. Isso não é magia, é reflexão em C# e sua "irmã mais nova" — a introspecção em C#.
Para que isso serve? Imagine que você está escrevendo um sistema de plugins, um desserializador JSON ou uma chamada dinâmica de métodos. Sem reflexão, você teria que escrever um monte de if-else. Com ela, bastam algumas linhas. Parece intrigante? Vamos descobrir.
Neste artigo, não vamos apenas passar pela teoria. Vamos escrever exemplos de código reais que você pode usar imediatamente em seus projetos. Você aprenderá como obter informações sobre qualquer tipo, criar um objeto "do nada", chamar um método privado e até mesmo ler atributos. E tudo isso — na linguagem C#, tão amada por sua rigidez e poder.
O que são reflexão e introspecção em C#? Diferença entre os conceitos
Frequentemente, esses termos são usados como sinônimos, mas há uma linha tênue entre eles:
- Introspecção em C# — é a capacidade do programa de observar sua própria estrutura. Você pode descobrir quais campos uma classe possui, quais métodos ela contém, quais atributos estão anexados. Mas você não altera nada.
- Reflexão em C# — é um conceito mais amplo. Ela inclui a introspecção, mais a capacidade de interagir com o código: chamar métodos, criar objetos, alterar valores de campos.
Simplificando: introspecção é "olhar", reflexão é "olhar e tocar". Em C#, ambas as funções são tratadas pelo namespace System.Reflection. Esta é sua principal ferramenta.
Exemplo prático: obtendo informações sobre o tipo (Type)
Tudo começa com a classe Type. Esta é a base da reflexão. Você pode obtê-la de três maneiras:
// Maneira 1: através de typeof()Type typeFromKeyword = typeof(string);
// Maneira 2: através da instância .GetType()string example = "Olá, mundo!";Type typeFromInstance = example.GetType();
// Maneira 3: através do assemblyType typeFromAssembly = Assembly.GetExecutingAssembly().GetType("System.String");Agora, tendo o objeto Type, podemos descobrir tudo sobre a classe. Vamos escrever um método útil para introspecção:
using System;using System.Reflection;
public class Inspector{ public static void ShowTypeInfo(Type type) { Console.WriteLine($"=== Informações sobre o tipo: {type.Name} ==="); Console.WriteLine($"Nome completo: {type.FullName}"); Console.WriteLine($"É uma classe? {type.IsClass}"); Console.WriteLine($"É abstrato? {type.IsAbstract}"); Console.WriteLine($"Classe base: {type.BaseType?.Name}"); Console.WriteLine("Propriedades públicas:"); foreach (PropertyInfo prop in type.GetProperties()) { Console.WriteLine($" - {prop.PropertyType.Name} {prop.Name}"); } Console.WriteLine("Métodos públicos:"); foreach (MethodInfo method in type.GetMethods()) { Console.WriteLine($" - {method.ReturnType.Name} {method.Name}({string.Join(", ", method.GetParameters().Select(p => $"{p.ParameterType.Name} {p.Name}"))})"); } }}
// UsoInspector.ShowTypeInfo(typeof(List<int>));/* Saída:=== Informações sobre o tipo: List`1 ===Nome completo: System.Collections.Generic.List`1[[System.Int32, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]É uma classe? TrueÉ abstrato? FalseClasse base: Object
Propriedades públicas: - Int32 Capacity - Int32 Count
Métodos públicos: - Void Add(Int32 obj) - Void Clear() - Boolean Contains(Int32 item) ... e muitos outros*/Isso é pura introspecção.