Reflection in C# is a powerful feature that allows you to inspect and interact with the metadata of types at runtime. This includes examining the properties, methods, and events of an object, as well as creating instances of types dynamically. Reflection is particularly useful for scenarios such as building frameworks, performing dynamic type discovery, and creating custom attributes.
Key Concepts
- Metadata: Information about the types defined in a program, such as classes, interfaces, and methods.
- System.Reflection Namespace: Contains classes that allow you to obtain information about assemblies, modules, members, parameters, and other entities in managed code.
- Type Class: Represents type declarations: class types, interface types, array types, value types, and enumeration types.
Practical Examples
Example 1: Inspecting a Type
Let's start by inspecting a simple class using reflection.
using System; using System.Reflection; public class Person { public string Name { get; set; } public int Age { get; set; } public void SayHello() { Console.WriteLine("Hello!"); } } class Program { static void Main() { Type personType = typeof(Person); Console.WriteLine("Properties of Person:"); foreach (PropertyInfo prop in personType.GetProperties()) { Console.WriteLine($"Property: {prop.Name}, Type: {prop.PropertyType}"); } Console.WriteLine("\nMethods of Person:"); foreach (MethodInfo method in personType.GetMethods()) { Console.WriteLine($"Method: {method.Name}, Return Type: {method.ReturnType}"); } } }
Explanation:
typeof(Person)
: Gets theType
object representing thePerson
class.GetProperties()
: Retrieves an array ofPropertyInfo
objects representing all the public properties of thePerson
class.GetMethods()
: Retrieves an array ofMethodInfo
objects representing all the public methods of thePerson
class.
Example 2: Creating an Instance Dynamically
You can also create an instance of a type dynamically using reflection.
using System; using System.Reflection; public class Person { public string Name { get; set; } public int Age { get; set; } public void SayHello() { Console.WriteLine("Hello!"); } } class Program { static void Main() { Type personType = typeof(Person); object personInstance = Activator.CreateInstance(personType); PropertyInfo nameProperty = personType.GetProperty("Name"); nameProperty.SetValue(personInstance, "John Doe"); PropertyInfo ageProperty = personType.GetProperty("Age"); ageProperty.SetValue(personInstance, 30); MethodInfo sayHelloMethod = personType.GetMethod("SayHello"); sayHelloMethod.Invoke(personInstance, null); Console.WriteLine($"Name: {nameProperty.GetValue(personInstance)}, Age: {ageProperty.GetValue(personInstance)}"); } }
Explanation:
Activator.CreateInstance(personType)
: Creates an instance of thePerson
class.GetProperty("Name")
: Retrieves thePropertyInfo
object for theName
property.SetValue(personInstance, "John Doe")
: Sets the value of theName
property to "John Doe".GetMethod("SayHello")
: Retrieves theMethodInfo
object for theSayHello
method.Invoke(personInstance, null)
: Invokes theSayHello
method on thepersonInstance
.
Practical Exercises
Exercise 1: Inspecting a Custom Class
Create a class named Car
with properties Make
, Model
, and Year
. Use reflection to list all the properties and methods of the Car
class.
Solution:
using System; using System.Reflection; public class Car { public string Make { get; set; } public string Model { get; set; } public int Year { get; set; } public void Drive() { Console.WriteLine("Driving..."); } } class Program { static void Main() { Type carType = typeof(Car); Console.WriteLine("Properties of Car:"); foreach (PropertyInfo prop in carType.GetProperties()) { Console.WriteLine($"Property: {prop.Name}, Type: {prop.PropertyType}"); } Console.WriteLine("\nMethods of Car:"); foreach (MethodInfo method in carType.GetMethods()) { Console.WriteLine($"Method: {method.Name}, Return Type: {method.ReturnType}"); } } }
Exercise 2: Dynamic Method Invocation
Create an instance of the Car
class dynamically and set its properties using reflection. Then, invoke the Drive
method.
Solution:
using System; using System.Reflection; public class Car { public string Make { get; set; } public string Model { get; set; } public int Year { get; set; } public void Drive() { Console.WriteLine("Driving..."); } } class Program { static void Main() { Type carType = typeof(Car); object carInstance = Activator.CreateInstance(carType); PropertyInfo makeProperty = carType.GetProperty("Make"); makeProperty.SetValue(carInstance, "Toyota"); PropertyInfo modelProperty = carType.GetProperty("Model"); modelProperty.SetValue(carInstance, "Corolla"); PropertyInfo yearProperty = carType.GetProperty("Year"); yearProperty.SetValue(carInstance, 2021); MethodInfo driveMethod = carType.GetMethod("Drive"); driveMethod.Invoke(carInstance, null); Console.WriteLine($"Make: {makeProperty.GetValue(carInstance)}, Model: {modelProperty.GetValue(carInstance)}, Year: {yearProperty.GetValue(carInstance)}"); } }
Common Mistakes and Tips
- Access Modifiers: Reflection can only access public members by default. To access non-public members, you need to use binding flags.
- Performance: Reflection is slower than direct code access. Use it judiciously, especially in performance-critical applications.
- Security: Be cautious when using reflection to invoke methods or access properties, as it can potentially expose private data or methods.
Conclusion
Reflection is a versatile tool in C# that allows you to inspect and manipulate types at runtime. It is particularly useful for dynamic type discovery, building frameworks, and creating custom attributes. However, it should be used judiciously due to its performance overhead and potential security implications. In the next topic, we will explore attributes, which are closely related to reflection and provide a way to add metadata to your code.
C# Programming Course
Module 1: Introduction to C#
- Introduction to C#
- Setting Up the Development Environment
- Hello World Program
- Basic Syntax and Structure
- Variables and Data Types
Module 2: Control Structures
Module 3: Object-Oriented Programming
- Classes and Objects
- Methods
- Constructors and Destructors
- Inheritance
- Polymorphism
- Encapsulation
- Abstraction
Module 4: Advanced C# Concepts
- Interfaces
- Delegates and Events
- Generics
- Collections
- LINQ (Language Integrated Query)
- Asynchronous Programming
Module 5: Working with Data
Module 6: Advanced Topics
- Reflection
- Attributes
- Dynamic Programming
- Memory Management and Garbage Collection
- Multithreading and Parallel Programming