Mastering Reflection in C#: Automate and Optimize Your Code
Introduction As developers, we often deal with scenarios where we need to inspect, modify, or invoke members of an object dynamically. Whether it’s for dependency injection, object mapping, unit testing, or plugin development, C#'s Reflection API provides powerful capabilities to analyze and manipulate types at runtime. In this post, we'll explore what Reflection is, how it works, its use cases in automating design pattern implementation, and best practices to ensure efficiency. What is Reflection in C#? Reflection is a runtime feature in C# that allows a program to inspect and interact with metadata, types, methods, properties, and fields of objects dynamically. It resides in the System.Reflection namespace and is commonly used when working with unknown types, plugins, serialization, and testing frameworks. Why Use Reflection? Dynamically Load and Invoke Methods – Call methods on objects whose type is unknown at compile time. Inspect Metadata – Retrieve information about assemblies, types, properties, and attributes. Create Objects Dynamically – Instantiate classes without knowing them beforehand. Automate Code Generation – Implement dynamic proxies and ORM mappers. How Reflection Works in C# The core of Reflection revolves around the Type class, which allows us to inspect types, retrieve members, and invoke methods dynamically. Basic Example of Reflection using System; using System.Reflection; class Program { static void Main() { Type type = typeof(SampleClass); Console.WriteLine("Class Name: " + type.Name); MethodInfo method = type.GetMethod("SayHello"); object instance = Activator.CreateInstance(type); method.Invoke(instance, null); } } class SampleClass { public void SayHello() { Console.WriteLine("Hello from Reflection!"); } } Breaking Down the Code Type type = typeof(SampleClass); – Retrieves metadata about SampleClass. GetMethod("SayHello") – Retrieves the SayHello method dynamically. Activator.CreateInstance(type) – Creates an instance of SampleClass. method.Invoke(instance, null); – Calls SayHello() dynamically. Reflection in Design Patterns Reflection is particularly powerful when automating design pattern implementations. Let’s explore how it can be used. 1. Implementing Factory Pattern with Reflection Instead of manually writing factory methods for multiple classes, we can use Reflection to dynamically create instances. Traditional Factory Method public class Factory { public static Product CreateProduct() => new Product(); } Factory Using Reflection using System; public class Factory { public static object CreateInstance(string className) { Type type = Type.GetType(className); return Activator.CreateInstance(type); } } // Usage var product = Factory.CreateInstance("Namespace.Product"); This approach allows us to instantiate classes dynamically by passing the class name as a string. 2. Automating Dependency Injection Reflection plays a crucial role in Dependency Injection (DI) frameworks like ASP.NET Core's built-in DI container, Autofac, and Unity. Creating a Simple DI Container Using Reflection using System; using System.Collections.Generic; using System.Reflection; public class SimpleDIContainer { private readonly Dictionary _mappings = new(); public void Register() { _mappings[typeof(TInterface)] = typeof(TImplementation); } public T Resolve() { Type implementationType = _mappings[typeof(T)]; return (T)Activator.CreateInstance(implementationType); } } // Usage interface IService { void Serve(); } class Service : IService { public void Serve() => Console.WriteLine("Service Called!"); } var container = new SimpleDIContainer(); container.Register(); var service = container.Resolve(); service.Serve(); // Output: Service Called! This demonstrates how Reflection enables dynamic object resolution in DI frameworks. 3. Dynamic Method Invocation for Plugin Systems Plugins or dynamically loaded modules often rely on Reflection to discover and invoke methods at runtime. Loading an Assembly and Invoking a Method Dynamically using System; using System.Reflection; Assembly assembly = Assembly.LoadFrom("ExternalPlugin.dll"); Type pluginType = assembly.GetType("ExternalPlugin.PluginClass"); MethodInfo method = pluginType.GetMethod("Execute"); object pluginInstance = Activator.CreateInstance(pluginType); method.Invoke(pluginInstance, null); This is particularly useful when loading external assemblies without recompiling the main application. Performance Considerations and Best Practices While Reflection is powerful, it comes with performance overhead. Here are some best practices to miti

Introduction
As developers, we often deal with scenarios where we need to inspect, modify, or invoke members of an object dynamically. Whether it’s for dependency injection, object mapping, unit testing, or plugin development, C#'s Reflection API provides powerful capabilities to analyze and manipulate types at runtime.
In this post, we'll explore what Reflection is, how it works, its use cases in automating design pattern implementation, and best practices to ensure efficiency.
What is Reflection in C#?
Reflection is a runtime feature in C# that allows a program to inspect and interact with metadata, types, methods, properties, and fields of objects dynamically. It resides in the System.Reflection
namespace and is commonly used when working with unknown types, plugins, serialization, and testing frameworks.
Why Use Reflection?
- Dynamically Load and Invoke Methods – Call methods on objects whose type is unknown at compile time.
- Inspect Metadata – Retrieve information about assemblies, types, properties, and attributes.
- Create Objects Dynamically – Instantiate classes without knowing them beforehand.
- Automate Code Generation – Implement dynamic proxies and ORM mappers.
How Reflection Works in C#
The core of Reflection revolves around the Type
class, which allows us to inspect types, retrieve members, and invoke methods dynamically.
Basic Example of Reflection
using System;
using System.Reflection;
class Program
{
static void Main()
{
Type type = typeof(SampleClass);
Console.WriteLine("Class Name: " + type.Name);
MethodInfo method = type.GetMethod("SayHello");
object instance = Activator.CreateInstance(type);
method.Invoke(instance, null);
}
}
class SampleClass
{
public void SayHello()
{
Console.WriteLine("Hello from Reflection!");
}
}
Breaking Down the Code
-
Type type = typeof(SampleClass);
– Retrieves metadata aboutSampleClass
. -
GetMethod("SayHello")
– Retrieves theSayHello
method dynamically. -
Activator.CreateInstance(type)
– Creates an instance ofSampleClass
. -
method.Invoke(instance, null);
– CallsSayHello()
dynamically.
Reflection in Design Patterns
Reflection is particularly powerful when automating design pattern implementations. Let’s explore how it can be used.
1. Implementing Factory Pattern with Reflection
Instead of manually writing factory methods for multiple classes, we can use Reflection to dynamically create instances.
Traditional Factory Method
public class Factory
{
public static Product CreateProduct() => new Product();
}
Factory Using Reflection
using System;
public class Factory
{
public static object CreateInstance(string className)
{
Type type = Type.GetType(className);
return Activator.CreateInstance(type);
}
}
// Usage
var product = Factory.CreateInstance("Namespace.Product");
This approach allows us to instantiate classes dynamically by passing the class name as a string.
2. Automating Dependency Injection
Reflection plays a crucial role in Dependency Injection (DI) frameworks like ASP.NET Core's built-in DI container, Autofac, and Unity.
Creating a Simple DI Container Using Reflection
using System;
using System.Collections.Generic;
using System.Reflection;
public class SimpleDIContainer
{
private readonly Dictionary<Type, Type> _mappings = new();
public void Register<TInterface, TImplementation>()
{
_mappings[typeof(TInterface)] = typeof(TImplementation);
}
public T Resolve<T>()
{
Type implementationType = _mappings[typeof(T)];
return (T)Activator.CreateInstance(implementationType);
}
}
// Usage
interface IService { void Serve(); }
class Service : IService { public void Serve() => Console.WriteLine("Service Called!"); }
var container = new SimpleDIContainer();
container.Register<IService, Service>();
var service = container.Resolve<IService>();
service.Serve(); // Output: Service Called!
This demonstrates how Reflection enables dynamic object resolution in DI frameworks.
3. Dynamic Method Invocation for Plugin Systems
Plugins or dynamically loaded modules often rely on Reflection to discover and invoke methods at runtime.
Loading an Assembly and Invoking a Method Dynamically
using System;
using System.Reflection;
Assembly assembly = Assembly.LoadFrom("ExternalPlugin.dll");
Type pluginType = assembly.GetType("ExternalPlugin.PluginClass");
MethodInfo method = pluginType.GetMethod("Execute");
object pluginInstance = Activator.CreateInstance(pluginType);
method.Invoke(pluginInstance, null);
This is particularly useful when loading external assemblies without recompiling the main application.
Performance Considerations and Best Practices
While Reflection is powerful, it comes with performance overhead. Here are some best practices to mitigate inefficiencies:
1. Cache Reflection Results
Repeated Reflection calls can slow down execution. Cache method/constructor info to improve performance.
Dictionary<string, MethodInfo> methodCache = new();
MethodInfo GetCachedMethod(Type type, string methodName)
{
if (!methodCache.ContainsKey(methodName))
methodCache[methodName] = type.GetMethod(methodName);
return methodCache[methodName];
}
2. Use Expression Trees for Faster Invocation
Instead of using MethodInfo.Invoke()
, use compiled expression trees for better performance.
using System;
using System.Linq.Expressions;
using System.Reflection;
public class ReflectionOptimized
{
public static Action<object> CreateMethodInvoker(MethodInfo method)
{
ParameterExpression instance = Expression.Parameter(typeof(object));
Expression call = Expression.Call(Expression.Convert(instance, method.DeclaringType), method);
return Expression.Lambda<Action<object>>(call, instance).Compile();
}
}
// Usage
MethodInfo method = typeof(SampleClass).GetMethod("SayHello");
var invoker = ReflectionOptimized.CreateMethodInvoker(method);
invoker(new SampleClass()); // Calls SayHello() efficiently
3. Avoid Overusing Reflection in Performance-Critical Code
Reflection should be used strategically, not as a replacement for direct method calls. In critical performance scenarios, consider alternatives like code generation (T4 Text Templates), dependency injection, or pre-compiled delegates.
Conclusion
Reflection in C# is an incredibly powerful tool for dynamic type inspection, method invocation, dependency injection, and plugin-based architectures. It enables greater flexibility and automation but should be used carefully to avoid performance pitfalls.