Reflection · TL;DR
2 min readTL;DR
A: Reflection is the ability to inspect and interact with type metadata at runtime via System.Reflection. Use it for scenarios where compile-time type knowledge is insufficient: plugin discovery, attribute-driven frameworks, serialization, DI container auto-registration, and tooling like test runners or ORM materializers.
typeof, GetType(), and Type.GetType()?A: typeof(T) is a compile-time operator that returns the Type for a known type. obj.GetType() returns the runtime type of an instance (always the concrete type, not the declared type). Type.GetType("name") resolves a type from a string, requiring an assembly-qualified name for types outside the calling assembly or mscorlib.
A: They scan assemblies for types implementing specific interfaces, inspect constructors to determine dependencies (ConstructorInfo.GetParameters()), resolve each parameter recursively, and invoke the constructor. Production containers cache constructor delegates after first resolution to avoid repeated reflection.
A: Source generators run during compilation and emit C# source code. Instead of discovering types/properties at runtime, the generated code contains explicit, strongly-typed logic. System.Text.Json source gen, for example, generates serializers that are faster, trimming-safe, and AOT-compatible.
A: Define a shared interface (e.g., IPlugin) in a common assembly. At startup, scan a plugins directory for .dll files, load each via Assembly.LoadFrom, find types implementing IPlugin, and instantiate them with Activator.CreateInstance. For production, add version validation, dependency isolation via AssemblyLoadContext, and error handling for partial loads.
A: Write unit tests for discovery logic (ensuring correct types are found) and integration tests that verify attributes/config drive expected behavior. Test trimming scenarios by publishing a trimmed build and running a smoke test. Mock metadata where possible by abstracting the reflection layer behind an interface.