Reflection – Runtime Internals
Reflection provides the ability to discover and interact with types, members, and metadata at runtime. It powers many high‑level features such as serialization, dependency injection, and dynamic proxies.
📖 Overview
At its core, reflection works through the System.Reflection namespace and the underlying CLR metadata tables. When you request a Type object, the runtime reads the assembly’s metadata streams and builds a runtime representation.
// Get a type at runtime
Type t = Type.GetType("System.Collections.Generic.List`1");
// List its public methods
foreach (var m in t.GetMethods())
Console.WriteLine(m.Name);
🔎 Type Inspection
Reflection can reveal base types, interfaces, generic arguments, custom attributes and more.
// Generic arguments
if (t.IsGenericType)
{
foreach (var arg in t.GetGenericArguments())
Console.WriteLine($"Generic arg: {arg}");
}
🔧 Member Access
Members (fields, properties, methods) can be inspected and invoked dynamically.
// Create an instance via reflection
object list = Activator.CreateInstance(t);
// Invoke Add method
MethodInfo add = t.GetMethod("Add");
add.Invoke(list, new object[] { 42 });
⚡ Dynamic Invocation
The System.Reflection.Emit API can generate IL at runtime for faster dynamic calls. The System.Linq.Expressions API provides a higher‑level way to compile delegates.
// Compile a getter using Expression
var param = Expression.Parameter(typeof(object), "target");
var cast = Expression.Convert(param, t);
var prop = Expression.Property(cast, "Count");
var lambda = Expression.Lambda<Func<object, int>>(prop, param);
Func<object, int> getCount = lambda.Compile();
int cnt = getCount(list); // cnt == 1
🚀 Performance Considerations
- Reflection is slower than static code – cache
MethodInfo/PropertyInfoobjects. - Use
RuntimeHelpers.GetUninitializedObjectfor low‑level scenarios. - Prefer
System.Linq.Expressionsor source generators for high‑frequency paths.