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
/PropertyInfo
objects. - Use
RuntimeHelpers.GetUninitializedObject
for low‑level scenarios. - Prefer
System.Linq.Expressions
or source generators for high‑frequency paths.