Need to peek inside your code while it's running? That's what .NET Reflection does. Here are 5 real ways developers use it:
Application | What It Does | When To Use |
---|---|---|
Plugin Systems | Loads new code without rebuilding | Adding features on-demand |
Data Validation | Checks data using attributes | Form validation, input checking |
Object Mapping | Copies data between objects | DTOs, API responses |
Test Frameworks | Finds and runs tests | Unit testing, mocking |
App Settings | Manages configuration | Reading/writing settings |
Important: Reflection trades speed for flexibility:
- It runs 30x slower than direct code
- Cached reflection is 33x faster than uncached
- Pre-compiled expressions are best for speed
Quick Tips:
- Cache reflection calls you'll use again
- Add security checks for private code
- Handle errors that pop up at runtime
- Test performance with real data
- Use regular code when types are known
Want the full details? Let's break down each use case with real code examples and performance numbers.
Related video from YouTube
How .NET Reflection Works
.NET Reflection is like X-ray vision for your code - it lets your program look at itself while running. Here's a simple example:
// Basic reflection example
String name = "Test";
Type type = name.GetType();
Console.WriteLine(type); // Outputs: System.String
The core pieces work together:
Component | What It Does | How To Use It |
---|---|---|
Assembly | Holds your code | Assembly.Load("MyLibrary.dll") |
Type | Maps your classes | typeof(DateTime) |
MethodInfo | Shows methods | type.GetMethod("ToString") |
PropertyInfo | Gets properties | type.GetProperty("Length") |
FieldInfo | Accesses fields | type.GetField("_count") |
Let's break down how to use it:
1. Load Your Code
Assembly testAssembly = Assembly.LoadFile(@"c:\Test.dll");
Type calcType = testAssembly.GetType("Test.Calculator");
2. Check Type Details
Type t = typeof(Enumerable);
Console.WriteLine($"Name: {t.Name}");
Console.WriteLine($"Namespace: {t.Namespace}");
3. Make New Objects
DateTime date = (DateTime)Activator.CreateInstance(typeof(DateTime));
Performance is key. Here's what you need to know:
Operation | Speed | What To Do |
---|---|---|
Property access | Slow | Save property info |
Object creation | Medium | Use compiled code |
Reading metadata | Fast | Nothing needed |
Make it faster by:
- Saving type info you'll use again
- Using
BindingFlags
to search less - Testing your specific use case
Know these boundaries:
What | Limit | Impact |
---|---|---|
Security | Can see private code | Need right permissions |
Speed | Not as fast as direct code | Cache when you can |
Errors | Found while running | Add extra checks |
The CLR manages assemblies in domains, keeping everything in check. This setup helps reflection do its job while keeping your code safe and controlled.
Building Plugin Systems
Want to add features to your app without touching the core code? That's what plugin systems do. Here's how to build one using reflection:
Let's start with a simple plugin contract:
namespace PluginBase {
public interface ICommand {
string Name { get; }
string Description { get; }
int Execute();
}
}
A plugin system needs these key parts:
Part | What It Does | How It Works |
---|---|---|
Contract | Sets the rules | Interface/abstract class that plugins must follow |
Implementation | Does the work | Class that brings the contract to life |
Loader | Finds plugins | Uses reflection to grab DLLs |
Here's a plugin loader that gets the job done:
foreach (Type t in assembly.GetTypes()) {
if (!t.IsInterface) {
var plugin = t.GetInterface(typeof(ICommand).Name);
if (plugin != null) {
ICommand p = (ICommand)Activator.CreateInstance(t);
plugins.Add(p);
}
}
}
Need to handle plugin dependencies? Here's what to do:
What | How | Why |
---|---|---|
Load assemblies | AssemblyLoadContext |
Keeps plugins separate |
Find dependencies | AssemblyDependencyResolver |
Maps DLL locations |
Check interfaces | Use full name checks | Prevents naming conflicts |
Make your plugin system better:
- Store plugins in their own folder
- Check plugin signatures
- Save loaded plugin types
- Test each plugin by itself
The result? Your app stays clean while plugins can change whenever needed.
2. Data Validation with Attributes
Data validation with attributes is a simple way to check your data using reflection. Here's what you need to know:
Attribute | Checks For | How To Use It |
---|---|---|
[Required] | Missing data | [Required(ErrorMessage = "Name is Required")] |
[EmailAddress] | Valid email | [EmailAddress(ErrorMessage = "Invalid email")] |
[StringLength] | Text length | [StringLength(100, MinimumLength = 6)] |
[Range] | Number limits | [Range(1, 100)] |
[Phone] | Phone numbers | [Phone] |
Want to make your own rules? Here's how to check if someone's 18 or older:
public class CustomerDateOfBirthValidation : ValidationAttribute {
private int MINIMUM_AGE = 18;
protected override ValidationResult? IsValid(object? value,
ValidationContext validationContext) {
if (!DateTime.TryParse(value?.ToString(), out DateTime dob)) {
return new ValidationResult("Invalid date format");
}
var minDateOfBirth = DateTime.Now.Date.AddYears(MINIMUM_AGE * -1);
if (dob > minDateOfBirth) {
return new ValidationResult("Must be 18 or older");
}
return ValidationResult.Success;
}
}
Add it to your model:
public class Customer {
[CustomerDateOfBirthValidation]
public DateTime DateOfBirth { get; set; }
}
Need to check if someone clicked "accept"? Use this:
[MustBeTrue(ErrorMessage = "Terms must be accepted")]
public bool AcceptTerms { get; set; }
What makes validation work better:
- Simple rules
- Clear messages
- Null checks
- Edge case tests
- Smart caching
Run your validation like this:
var context = new ValidationContext(customer);
var results = new List<ValidationResult>();
bool isValid = Validator.TryValidateObject(customer, context, results, true);
That's it! Your validation rules stay clean and you can use them anywhere in your app.
3. Object Mapping Made Simple
Let's break down object mapping in C# - it's just copying data between different objects. Here's what you need to know:
Mapping Approach | Speed | Use Case | Code Complexity |
---|---|---|---|
Manual Mapping | Fast | Simple mappings | Low |
Reflection | Medium | Dynamic mappings | Medium |
AutoMapper | Slower | Complex mappings | Low |
Here's a basic property copier using reflection:
public class PropertyCopier<TParent, TChild>
where TParent : class
where TChild : class {
public static void Copy(TParent parent, TChild child) {
var parentProps = parent.GetType().GetProperties();
var childProps = child.GetType().GetProperties();
foreach (var parentProp in parentProps) {
foreach (var childProp in childProps) {
if (parentProp.Name == childProp.Name &&
parentProp.PropertyType == childProp.PropertyType) {
childProp.SetValue(child, parentProp.GetValue(parent));
break;
}
}
}
}
}
Want to see it in action? Here's how:
var customer = new CustomerDataModel {
Name = "Jane Smith",
Start = DateTimeOffset.Now
};
var viewModel = new CustomerViewModel();
PropertyCopier<CustomerDataModel, CustomerViewModel>.Copy(customer, viewModel);
Need more control? Add attributes to your properties:
public class CustomerViewModel {
[MatchParent("FullName")]
public string Name { get; set; }
[MatchParent("StartDate")]
public DateTimeOffset Start { get; set; }
}
"If your AutoMapper mappings are trivial, why not map with trivial code? It's dumb code, but I like dumb code for dumb tasks." - Anthony Steele, Author
Here's what makes mapping work better:
- Add null checks
- Handle different types
- Store property info
- Test weird cases
- Keep it simple
Want speed? Use pre-compiled mapping - it's 3x faster than basic reflection. This works great for object-to-dictionary mapping or when you know your types upfront.
Bottom line: Pick what fits. Manual mapping for simple stuff, reflection when you need flexibility, AutoMapper when things get complex.
4. Building Test Frameworks
Test frameworks need three core functions: finding tests, running them, and showing results. Here's how reflection makes it happen:
Task | Reflection Method | What It Does |
---|---|---|
Find Tests | Attribute scanning | Spots [TestMethod] and [Test] markers |
Run Tests | Runtime execution | Calls test methods automatically |
Access Code | Member access | Gets to private and internal code |
Test Control | Custom attributes | Switches features on/off |
Here's a simple test runner that shows reflection in action:
public class TestRunner {
private int _total, _passed, _failed;
public void RunTests(Assembly assembly) {
var testClasses = assembly.GetTypes()
.Where(t => t.GetCustomAttribute<TestClassAttribute>() != null);
foreach(var testClass in testClasses) {
var testMethods = testClass.GetMethods()
.Where(m => m.GetCustomAttribute<TestMethodAttribute>() != null);
foreach(var method in testMethods) {
try {
var instance = Activator.CreateInstance(testClass);
method.Invoke(instance, null);
_passed++;
} catch {
_failed++;
}
_total++;
}
}
}
}
Need to test private code? PrivateObject
makes it simple:
[TestMethod]
public void TestPrivateMethod() {
var obj = new PrivateObject(typeof(MyClass));
var result = obj.Invoke("PrivateMethod", 42);
Assert.AreEqual(expected, result);
}
Want feature flags in your tests? Add a custom attribute:
[FeatureFlagTest("newFeature", true)]
public void TestWithFeatureEnabled() {
// Test code here
}
"I wanted something simpler, and similar to something like Python decorators, where in we can just use an attribute to decorate the test with desired configuration for the feature flag." - Mitesh Shah, Author
Make your test tools better:
- Store reflection data to boost speed
- Set up and clean up tests properly
- Show clear error messages
- Keep track of test times
- Group tests by category
Testing internal code? Add this to AssemblyInfo.cs:
[assembly: InternalsVisibleTo("TestProject")]
This opens up internal code to your test project - no reflection tricks needed.
sbb-itb-29cd4f6
5. Managing App Settings
Here's how reflection simplifies app settings management and cuts down manual coding:
Task | Reflection Method | What It Does |
---|---|---|
Load Settings | GetProperties() | Pulls all settings class properties |
Save Settings | SetValue() | Changes values while app runs |
Access Config | GetSection() | Gets data from appsettings.json |
Type Conversion | GetType() | Manages different data types |
Here's a self-managing settings class:
public class Settings {
public void Save() {
var composite = new ApplicationDataCompositeValue();
Type type = this.GetType();
foreach (var property in type.GetProperties()) {
string name = property.Name;
var value = property.GetValue(null);
composite[name] = value;
}
ApplicationData.Current.LocalSettings.Values["AppSettings"] = composite;
}
public void Load() {
var settings = ApplicationData.Current.LocalSettings;
if (settings.Values.ContainsKey("AppSettings")) {
var composite = (ApplicationDataCompositeValue)settings.Values["AppSettings"];
Type type = this.GetType();
foreach (var property in type.GetProperties()) {
if (composite.Keys.Contains(property.Name)) {
property.SetValue(type, composite[property.Name], null);
}
}
}
}
}
For ASP.NET apps, here's how to pull settings from appsettings.json:
var appSettings = _configuration.GetSection("EmailSettings")
.AsEnumerable()
.Where(x => x.Value != null)
.ToDictionary(
x => x.Key.Replace("EmailSettings:", ""),
x => x.Value
);
5 ways to boost settings performance:
- Cache reflection data
- Add type validation
- Set fallback values
- Switch to XML/JSON format
- Handle data errors
Need settings on the fly? Try this:
public static T GetSetting<T>(string key) {
var property = typeof(Settings)
.GetProperty(key, BindingFlags.Public | BindingFlags.Static);
return (T)property.GetValue(null);
}
This code lets you grab settings by name - no type knowledge needed.
Making Reflection Faster
Here's what happens when you compare direct method calls to reflection:
Method Type | Execution Time | Performance Ratio |
---|---|---|
Direct Call | 127 ms | 1x |
Reflection Call | 3.5 seconds | 30x slower |
Cached Reflection | 95 ms | 33x faster than uncached |
Want to make reflection run faster? Here's how:
1. Cache Everything
Put your Type, MethodInfo, and PropertyInfo lookups in a dictionary:
private static Dictionary<string, PropertyInfo> _propertyCache
= new Dictionary<string, PropertyInfo>();
public static PropertyInfo GetCachedProperty(string name) {
if (!_propertyCache.ContainsKey(name)) {
_propertyCache[name] = typeof(MyClass)
.GetProperty(name, BindingFlags.Public | BindingFlags.Instance);
}
return _propertyCache[name];
}
2. Use Delegates
Turn reflection calls into delegates:
var method = typeof(List<int>).GetMethod("Add");
var del = (Action<List<int>, int>)Delegate
.CreateDelegate(typeof(Action<List<int>, int>), method);
3. Apply DynamicMethod
When you need the BEST performance:
var dynamicMethod = new DynamicMethod(
"FastPropertyGet",
typeof(object),
new Type[] { typeof(object) },
typeof(PropertyAccessor).Module
);
Here's what happens with 5000 items:
Implementation | Time (μs) | Memory Usage |
---|---|---|
Base Code | 2,809.60 | Baseline |
Raw Reflection | 281,215.52 | High |
Cached Reflection | 95,066.90 | Medium |
Dynamic Method | 3,012.45 | Low |
"The point of the original speed comparison is to show that using Reflection to call a method is 30 times slower than making a direct call." - Jeremy Bytes, Author and Presenter
To keep your code fast:
- Load types when your app starts
- Build delegate caches right away
- Switch to interfaces after loading
- Don't use reflection for code that runs often
- Check your speed with big data sets
Tips for Using Reflection
Here's how to make reflection work better in your code:
Area | Key Tips |
---|---|
Security | - Check all input before using reflection - Keep MethodInfo parameters private - Set up proper permissions in your app domain |
Performance | - Pre-compile expressions you'll use often - Store PropertyInfo and FieldInfo objects - Pick generated methods over reflection calls |
Error Handling | - Add try-catch blocks to reflection code - Look for null values before member access - Make sure types match before casting |
Block Unwanted Reflection
Here's code to stop reflection when you don't want it:
public void EnsureNotCalledFromReflection()
{
var stack = new System.Diagnostics.StackTrace();
if (stack.ToString().Contains("System.Reflection"))
{
throw new InvalidOperationException("Reflection access not allowed");
}
}
Speed Test Results
Operation Type | Time (μs) | Memory Impact |
---|---|---|
Direct Property Access | 0.305024 | Minimal |
Expression Compilation | 44.375068 | Medium |
Delegate Creation | 0.3465711 | Low |
Keep It Safe
// Make sure code has permission to use reflection
if (!assembly.IsFullyTrusted)
{
throw new SecurityException("Untrusted assemblies cannot use reflection");
}
What Not to Do
- Run reflection code over and over without saving results
- Skip security checks
- Forget to check types
- Leave out error handling
- Use private members without thinking it through
"Only trusted code can use reflection to access security-critical members starting from .NET Framework 4." - Microsoft .NET Documentation
Document Everything
Element | What to Write Down |
---|---|
Purpose | Why you picked reflection over direct calls |
Security | What permissions your code needs |
Performance | How you'll save results for speed |
Maintenance | Ways to check types and handle errors |
The numbers show why smart reflection usage matters:
- Pre-compiled expressions run 20 times faster than
Activator.CreateInstance
- Property access with pre-compiled expressions beats
PropertyInfo.SetValue
by 50 times - Saving delegates makes your code 10 times faster than basic reflection
Summary
Here's what matters most about .NET Reflection:
Application | Main Benefits | Common Uses |
---|---|---|
Plugin Systems | Load code on demand | Add features without rebuilding |
Data Validation | Check data automatically | Read attributes, apply rules |
Object Mapping | Switch between types | Map DTOs, handle JSON/XML |
Test Frameworks | Look inside code | Find tests, set up mocks |
App Settings | Handle settings | Read/update properties |
Speed and Memory
Method | Speed | Memory |
---|---|---|
Direct Access | 0.3 μs | Tiny |
Cached Reflection | 0.35 μs | Small |
Raw Reflection | 44.37 μs | Medium |
Make It Work Better
- Store reflection results - don't look things up twice
- Add error handling for missing stuff
- Check permissions for private members
- Use binding flags to search smarter
"Using reflection efficiently is like haggling with an API. You have to pay to play and make some concessions. But it's worth it." - Joel Pobar, Program Manager, Microsoft CLR team
Stay Safe
- Set app domain permissions right
- Look at assembly trust
- Clean input before reflection
- Keep method info private
- Use try-catch blocks
Want more .NET tips? Get the .NET Newsletter.
Bottom Line: Use reflection when you need to check types or change stuff while your code runs. If you know what you need at compile time, just write regular code instead.
Learn More
Here's what you need to know about .NET Reflection tools and performance:
Library | What It Does | Speed Boost |
---|---|---|
Fasterflect | Makes reflection faster + clones objects | 5-100x faster |
Soenneker.Reflection.Cache | Speeds up common operations | Up to 24,842% faster |
Namotion.Reflection | Handles XML docs + nullable types | - |
Speed Comparison
Method | Performance | When to Use |
---|---|---|
Pre-compiled Expressions | 20x faster | High-volume operations |
Cached Reflection | 3-6x faster | Regular reflection |
Expression Compilation | 44.37 μs | Property operations |
Real Performance Numbers
Operation | Standard Speed | Cached Speed |
---|---|---|
Get Type | 1,022.30 ns | 17.52 ns |
Get Methods | 256.526 ns | 1.030 ns |
Get Members | 550.2334 ns | 0.6579 ns |
Here's what makes reflection FAST:
- Cache your reflection calls
- Use pre-compiled expressions
- Keep an eye on performance
- Test your code speed
Want to stay updated? Check out the .NET Newsletter.
"Performance matters in .NET apps. The right tools make all the difference." - Mo Mulla, Founder of Parental Questions
Key Resources:
- Microsoft's .NET Reflection docs
- TryAtSoftware benchmarks
- Application Insights monitoring
FAQs
What is reflection in .net with an example?
Reflection in .NET is a way to peek inside your code while it's running. Think of it like X-ray vision for your programs - you can see and work with parts that are usually hidden.
Here's what reflection lets you do:
What You Can Do | How It Works | Code Example |
---|---|---|
Look Up Types | Check what kind of data you're working with | int i = 42; Type type = i.GetType(); |
Make New Objects | Create objects without knowing their type beforehand | var obj = Activator.CreateInstance(Type.GetType(assemblyName)); |
Call Methods | Run methods by their names | method.Invoke(instance, null); |
Access Hidden Data | Read or change private stuff | field.GetValue(instance); |
Want to see reflection in action? Here's a simple example that calls a private method:
using System.Reflection;
var instance = new Target();
var method = typeof(Target)
.GetMethod("GetSecret",
BindingFlags.Instance |
BindingFlags.NonPublic);
var result = method.Invoke(instance, null);
// Output: "42"
This code shows how reflection helps you:
- Test private methods
- Build plugin systems
- Create frameworks
- Handle types that change while your code runs
It's like having a master key that opens any door in your code - just remember to use it wisely!