Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Reflection in C#: 4 Code Simple But Powerful Code Examples

5.00/5 (11 votes)
1 Mar 2024CPOL8 min read 13.4K  
In this article, I’ll provide you with 4 simple code examples illustrating how reflection works in C#.
Reflection in C# empowers developers to dynamically inspect and manipulate code during runtime, offering immense flexibility and creative potential. Through examples, this article demonstrates how reflection enables the retrieval of type information, access to non-public members, modification of object data and behavior, and dynamic object creation, emphasizing the responsibility that comes with its powerful capabilities.

Reflection in C# is a powerful feature that allows you to inspect and manipulate code at runtime. If that sounds like some fancy programming magic, it’s because it basically is. And you know what they say — with great power, comes great responsibility.

Reflection in C# provides us with the ability to examine types, their members, and invoke methods dynamically, opening up a world of possibilities for creative programs. In this article, I’ll provide you with 4 simple code examples illustrating how reflection works in C#.

What’s in This Article: Reflection in C#

Example 1: Retrieving Type Information Using Reflection in C#

Reflection in C# allows us to examine and manipulate types at runtime. It gives us the ability to retrieve information about classes, interfaces, methods, properties, and more. Understanding how to retrieve types using reflection is important for more complex and creative applications in C#.

To retrieve types using reflection, we can use the Type class from the System namespace. The Type class provides various methods and properties to work with types dynamically. Here’s an example code snippet that demonstrates how to retrieve types using reflection:

C#
using System;

public class Program
{
    public static void Main()
    {
        // Get the type of a class
        Type carType = typeof(Car);
        Console.WriteLine($"Type Name: {carType.Name}");

        // Get all public methods of a class
        MethodInfo[] methods = carType.GetMethods();
        Console.WriteLine("Methods:");
        foreach (MethodInfo method in methods)
        {
            Console.WriteLine($"- {method.Name}");
        }

        // Get all properties of a class
        PropertyInfo[] properties = carType.GetProperties();
        Console.WriteLine("Properties:");
        foreach (PropertyInfo property in properties)
        {
            Console.WriteLine($"- {property.Name}");
        }
    }
}

public class Car
{
    public string Make { get; set; }
    public string Model { get; set; }

    public void StartEngine()
    {
        Console.WriteLine("Engine started");
    }

    public void StopEngine()
    {
        Console.WriteLine("Engine stopped");
    }
}

In the above code, we first use the typeof operator to get the type of the Car class. Then, we can access various information about the type. In this example, we retrieve the type’s name, all public methods, and all properties. Running this code will output the following:

Type Name: Car
Methods:
- StartEngine
- StopEngine
Properties:
- Make
- Model

Retrieving types using reflection can be useful in a variety of scenarios. For example, you might want to dynamically load and instantiate classes based on user input or configuration data. Reflection also enables you to inspect the structure and behavior of code at runtime, and this opens up some doors when you need to make decisions based on information that you don’t have at compile time.

Example 2: Accessing Non-Public Members Using Reflection in C#

We previously saw how we could access things like public methods and properties that are available on types. As mentioned, this can have many helpful use-cases but it doesn’t *quite* feel like the scary stories we might have heard about reflection. Let’s change that up a bit.

While reflection in C# allows us to look up this information, we can also look up non-public information about types. That’s right. All of that effort that someone put in place to use private/protected and hide details from us on the outside? Gone. We can see everything we want! Muahaha! Oh, right — with great power comes great responsibility. No more evil laughter.

Here’s an example code snippet that demonstrates how to access non-public members using reflection:

C#
using System;
using System.Reflection;

public class Person
{
    private string _name;

    privateint Age { get; set; }

    private void SayHello()
    {
        Console.WriteLine("Hello!");
    }
}

public class Program
{
    public static void Main()
    {
        Type personType = typeof(Person);

        // Accessing a field using reflection
        FieldInfo nameField = personType.GetField(
            "_name",
            BindingFlags.NonPublic | BindingFlags.Instance);
        Console.WriteLine($"Field Name: {nameField.Name}");

        // Accessing a private property using reflection
        PropertyInfo ageProperty = personType.GetProperty(
            "Age"
            BindingFlags.NonPublic | BindingFlags.Instance);
        Console.WriteLine($"Property Name: {ageProperty.Name}");

        // Accessing a private method using reflection
        MethodInfo sayHelloMethod = personType.GetMethod(
            "SayHello",
            BindingFlags.NonPublic | BindingFlags.Instance);
        Console.WriteLine($"Method Name: {sayHelloMethod.Name}");
    }
}

In the above code, we define a Person class with a private field name, a private property Age, and a private method SayHello. In the Main method, we obtain the Type object for the Person class using typeof(Person). Using reflection, we can access the field, property, and method by specifying their names and using the GetField, GetProperty, and GetMethod methods of the Type type, respectively, to retrieve the corresponding members.

But the super important part here? The BindingFlags enum. We can ask for instance members that are non-public. We combine these two categories of members together using flag enums, which you can learn more about here in this video:

Example 3: Modifying Objects Using Reflection

Reflection in C# not only allows us to inspect and retrieve information about objects, but it also gives us the power to modify their data and behavior dynamically at runtime. This means that we can, at runtime, get a member by name (and other conditions) and then make modifications — effectively bypassing a lot of the compile-time checks we normally get. And… we can combine that with the non-public access we just saw! Keep that maniacal evil laughter under control…

To illustrate how modifying objects using reflection works, let’s consider a scenario where we have a simple Person class with properties representing their name and age:

C#
public class Person
{
    public string Name { get; set; }
    
    // NOTE: this probably makes no sense to ever
    // just have a private property like this here
    // but it's just for demonstration
    private int Age { get; set; }

    public void PrintInfo()
    {
        Console.WriteLine($"{Name} - {Age} years old");
    }
}

Now, let’s say we want to change the age of a Person object dynamically based on some condition. With reflection, we can achieve this by accessing and modifying the Age property at runtime.

C#
// Create a new instance of the Person class
Person person = new Person()
{
    Name = "Dev Leader",
};

// Get the Type object for the Person class
Type personType = typeof(Person);

// Get the PropertyInfo object for the Age property
PropertyInfo ageProperty = personType.GetProperty(
    "Age",
    BindingFlags.NonPublic | BindingFlags.Instance);

// Set the value of the Age property to 35
ageProperty.SetValue(person, 35);

// Prints "Dev Leader - 35 years old")
person.PrintInfo();

In this code example, we first create an instance of the Person class. Then, using reflection, we obtain the Type object for the Person class. From the Type object, we retrieve the PropertyInfo object for the Age property, which is private and not accessible to us traditionally from the outside. Finally, we use the SetValue method of the PropertyInfo object to modify the Age property of the person object to 35. When we ask the instance to print its info, we see the updated value!

While being able to modify objects dynamically can be incredibly powerful, it also comes with some risks and considerations. Modifying objects using reflection can introduce complexity and potential pitfalls (read that as: “will likely break things”), such as breaking encapsulation and violating the intended behavior of the object. It’s important to exercise caution and ensure that the modifications made using reflection align with the design and requirements of the system — this *probably* shouldn’t be your first course of action for many things.

Example 4: Creating Objects Using Reflection

Reflection in C# allows us to create instances of types dynamically. This means that we can create objects of a certain class without knowing the class name at compile-time. This flexibility can be particularly useful in scenarios where we need to dynamically instantiate objects based on runtime data or configuration.

To create an object dynamically using reflection, we need to follow a few steps:

  • We need to obtain a Type object that represents the class we want to create an instance of. We can do this by using the Type.GetType() method and passing the fully qualified name of the class as a string.
  • We can use the Activator.CreateInstance() method to create an instance of the class. This method takes the Type object as a parameter and returns a new instance of the class. We can then cast this instance to the desired type and use it as needed.

Let’s take a look at an example:

C#
string className = "MyNamespace.MyClass";
Type classType = Type.GetType(className);
object instance = Activator.CreateInstance(classType);
MyClass myObject = (MyClass)instance;

In the code above, we start by defining the fully qualified name of the class we want to create an instance of (MyNamespace.MyClass). We then obtain the Type object by calling Type.GetType() and passing the class name as a string. Next, we use Activator.CreateInstance() to create a new instance of the class and cast it to the desired type (MyClass in this case).

Creating objects dynamically using reflection can be useful in various scenarios, including:

  • A plugin system where we want to load different plugins at runtime. By using reflection, we can dynamically create instances of the plugin classes based on configuration or user input.
  • Dynamic object creation when working with deserialization. For example, if we receive JSON or XML data and need to map it to different classes based on the data content, reflection in C# can help us create the appropriate objects dynamically.

Remember to handle exceptions and ensure proper error-checking when working with reflection and dynamically creating objects! It’s easy to forget that reflection opens some funky doors that we really need to be careful with.

Showcase of Reflection in C#

Reflection in C# is a powerful tool that every C# developer should get familiar with because even if you don’t need to use it regularly, it’s helpful to understand. Reflection allows us to examine and manipulate objects at runtime, providing us with great flexibility and control over code in some creative situations — like plugin loading! By leveraging reflection, we can dynamically load types, query and invoke methods, access properties, and even create new objects.

Throughout this article, we explored four code examples that showcased how you can leverage reflection in C#. We discussed how to iterate through members, inspect things that aren’t publicly available, retrieve and set property values dynamically, and dynamically create instances of objects. If you found this useful and you’re looking for more learning opportunities, consider checking out my free videos on YouTube!

Frequently Asked Questions: What is Reflection in C#

What is reflection in C#?

Reflection in C# is a powerful feature that allows programmers to inspect and manipulate types, members, and objects at runtime.

Why is understanding reflection important for C# developers?

Understanding reflection in C# is important for software engineers because it enables them to create flexible and dynamic applications, perform advanced debugging and logging, and build frameworks and libraries that leverage runtime information.

How can types be retrieved using reflection?

Types can be retrieved using reflection in C# by using methods such as Type.GetType, Assembly.GetTypes, or Type.GetNestedTypes.

What can be accessed using reflection in C#?

Using reflection in C#, you can access fields, properties, methods, events, and constructors of types at runtime.

How can object data and behavior be modified using reflection?

Reflection in C# allows programmers to dynamically modify field values, property values, and method behavior of objects through the use of PropertyInfo, FieldInfo and MethodInfo respectively.

How can objects be created dynamically using reflection?

Objects can be created dynamically using reflection in C# by invoking the appropriate constructor using Activator.CreateInstance or Type.InvokeMember methods.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)