Reflection

Intro

Reflection is runtime metadata inspection and dynamic member access through System.Reflection. It is the mechanism behind many framework features (DI containers, serializers, test discovery, plugin loading), but it trades compile-time guarantees for runtime flexibility. In practice, use reflection when the target type/member is unknown until runtime, and avoid it on hot paths unless you cache metadata or compile delegates.

How It Works

At runtime, the CLR exposes assembly/type/member metadata via objects like Type, MethodInfo, PropertyInfo, and ConstructorInfo.

Typical flow:

  1. Get a Type (typeof(T), obj.GetType(), or loading an assembly).
  2. Select members using APIs like GetMethods, GetProperty, GetConstructors with BindingFlags.
  3. Read metadata (Name, Attributes, parameters, custom attributes).
  4. Optionally invoke dynamically (MethodInfo.Invoke) or construct instances (Activator.CreateInstance).
using System;
using System.Linq;
using System.Reflection;

Type t = typeof(string);
MethodInfo[] publicInstanceMethods = t.GetMethods(BindingFlags.Public | BindingFlags.Instance);

foreach (var m in publicInstanceMethods)
{
    Console.WriteLine($"{m.Name}({string.Join(", ", m.GetParameters().Select(p => p.ParameterType.Name))})");
}

Common Patterns

Example (attribute lookup + invoke):

using System;
using System.Linq;
using System.Reflection;

[AttributeUsage(AttributeTargets.Method)]
public sealed class JobAttribute : Attribute
{
    public string Name { get; }
    public JobAttribute(string name) => Name = name;
}

public sealed class Jobs
{
    [Job("rebuild-index")]
    public void RebuildIndex() => Console.WriteLine("Index rebuilt");
}

var target = new Jobs();
var method = typeof(Jobs)
    .GetMethods(BindingFlags.Public | BindingFlags.Instance)
    .FirstOrDefault(m => m.GetCustomAttribute<JobAttribute>()?.Name == "rebuild-index");

method?.Invoke(target, null);

Pitfalls

Tradeoffs

Questions


Whats next