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.
Reflection in .NET offers several benefits, such as:
Some common uses of reflection in .NET include:
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.
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.
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.
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 frameworks and Inversion of Control (IoC) containers often use reflection to automatically wire up dependencies between classes and manage object lifetimes.
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}");}}}}
Line 9: This line retrieves the current executing assembly using the Assembly.GetExecutingAssembly()
method and assigns it to the variable assembly
.
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 the types
variable
Lines 14–24: The code iterates through each Type
object in the types
array using a foreach
loop. 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. The FullName
property of the Type
class 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 Type
object using type.GetMethods()
. The methods are stored in the methods
variable.
Line 22–24: Inside the nested loop, the code prints the name of each method to the console using Console.WriteLine()
. The Name
property of the MethodInfo
class provides the name of the method.
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