What is reflection in .NET?
In .NET, reflection is a powerful feature that allows us to inspect and manipulate types, classes, methods, properties, and other members of assemblies at runtime. With reflection, we can access and analyze metadata about the types defined in an assembly, and even invoke methods, create instances, or modify properties dynamically without knowing their details at compile time.
Advantages of reflection
Reflection in .NET offers several benefits, such as:
- Allows inspecting and modifying code at runtime
- Provides access to metadata about code
- Enables calling methods dynamically
- Supports using attributes for configuration
- Facilitates generating code on impulse
- Helps find and work with different types of code
- Useful for flexible and extensible applications
- Makes code more dynamic and adaptable
Common uses of reflection
Some common uses of reflection in .NET include:
Type discovery
We can use reflection to enumerate and discover types defined in an assembly, query their properties, methods, and events, and get information about their base types and interfaces.
Dynamic invocation
Reflection allows us to invoke methods and constructors on objects or types dynamically at runtime, even if we don’t have a compile-time reference to those methods.
Attribute handling
Attributes in .NET are used for metadata and configuration purposes. Reflection enables us to inspect and use attributes associated with types and members to provide additional information or behavior to our code.
Dynamic code generation
Reflection can be used to create and compile code dynamically at runtime. This is particularly useful when building code generators or custom scripting engines.
Dependency injection and IoC containers
Dependency injection frameworks and Inversion of Control (IoC) containers often use reflection to automatically wire up dependencies between classes and manage object lifetimes.
Coding example
Here’s a simple C# example demonstrating some basic reflection usage:
using System;using System.Reflection;class Program{static void Main(){// Load an assembly (e.g., the current executing assembly)Assembly assembly = Assembly.GetExecutingAssembly();// Get types defined in the assemblyType[] types = assembly.GetTypes();foreach (Type type in types){// Print the name of each typeConsole.WriteLine($"Type: {type.FullName}");// Get methods of the type and print their namesMethodInfo[] methods = type.GetMethods();foreach (MethodInfo method in methods){Console.WriteLine($" Method: {method.Name}");}}}}
Explanation
Line 9: This line retrieves the current executing assembly using the
Assembly.GetExecutingAssembly()method and assigns it to the variableassembly.Line 12: Here, the code obtains an array of all the types defined in the loaded assembly using
assembly.GetTypes()method, and stores it in thetypesvariableLines 14–24: The code iterates through each
Typeobject in thetypesarray using aforeachloop. This loop processes each type defined in the assembly.Line 17: Here, the code prints the full name of each type to the console using the
Console.WriteLine()method. TheFullNameproperty of theTypeclass provides the fully qualified name of the type.Lines 20: Within the type loop, the code retrieves an array of all the methods defined in the current
Typeobject usingtype.GetMethods(). The methods are stored in themethodsvariable.Line 22–24: Inside the nested loop, the code prints the name of each method to the console using
Console.WriteLine(). TheNameproperty of theMethodInfoclass provides the name of the method.
Summary
Reflection is a powerful tool, but it should be used carefully because it can introduce performance overhead and make the code harder to understand. When possible, it’s recommended to use static typing and compile-time checking instead of relying heavily on reflection. However, in scenarios where dynamic behavior is required, reflection can be a valuable asset.
Free Resources