DEV Community

Cover image for Reflection In C#: 4 Simple But Powerful Code Examples
Dev Leader
Dev Leader

Posted on • Originally published at devleader.ca

Reflection In C#: 4 Simple But Powerful Code Examples

The post Reflection in C#: 4 Code Simple But Powerful Code Examples appeared first on Dev Leader.

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#.


Example 1: Retrieving Type Information Using Reflection in CSharp

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:

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");
    }
}
Enter fullscreen mode Exit fullscreen mode

In the above code, we first use the typeofoperator 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
Enter fullscreen mode Exit fullscreen mode

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. See how this works in this video tutorial:

Dev Leader Weekly | Substack

My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers.

favicon weekly.devleader.ca

Example 2: Accessing Non-Public Members Using Reflection in CSharp

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:

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}");
    }
}
Enter fullscreen mode Exit fullscreen mode

In the above code, we define a Person class with a private fieldname, 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:

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");
    }
}
Enter fullscreen mode Exit fullscreen mode

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.

// 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();
Enter fullscreen mode Exit fullscreen mode

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. Learn more about private access and modification in this video tutorial:


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:

string className = "MyNamespace.MyClass";
Type classType = Type.GetType(className);
object instance = Activator.CreateInstance(classType);
MyClass myObject = (MyClass)instance;
Enter fullscreen mode Exit fullscreen mode

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 CSharp

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 subscribing to my free weekly software engineering newsletter and check out my free videos on YouTube!

Dev Leader Weekly | Substack

My weekly newsletter that simplifies software engineering for you, along with C# code examples. Join thousands of software engineers from companies like Microsoft and Amazon who are already reading! Click to read Dev Leader Weekly, a Substack publication with thousands of subscribers.

favicon weekly.devleader.ca

Want More Dev Leader Content?

  • Follow along on this platform if you haven’t already!
  • Subscribe to my free weekly software engineering and dotnet-focused newsletter. I include exclusive articles and early access to videos: SUBSCRIBE FOR FREE
  • Looking for courses? Check out my offerings: VIEW COURSES
  • E-Books & other resources: VIEW RESOURCES
  • Watch hundreds of full-length videos on my YouTube channel: VISIT CHANNEL
  • Visit my website for hundreds of articles on various software engineering topics (including code snippets): VISIT WEBSITE
  • Check out the repository with many code examples from my articles and videos on GitHub: VIEW REPOSITORY

Top comments (2)

Collapse
 
alassane-developer profile image
alassane-developer • Edited

Great !!!
So we can use reflection to test a private method for example? Indeed we often don't need to test private method but just the public caller.
Is it a bad approach?

Collapse
 
devleader profile image
Dev Leader

In my opinion - Yes, this is a very very bad approach. 99% of the time this is absolutely not what you want to be doing.

But I am very glad that you asked this question. If you find that you need to use reflection to test a private method, I would highly suggest you reconsider how your class has been designed. If you truly need unit-test style coverage on a private method and the only way to access it is via other methods, it might be an opportunity to extract this via refactoring and put it onto another dedicated dependency.

In my professional experience, the only times I ever need to use reflection for testing private things:

  • We need to deploy a CRITICAL bug fix in some legacy code. We don't have time to refactor it to test it "properly" but we want to have some confidence that we can test our change to some degree. We might go do something like this to get the confidence we need, and then afterwards reschedule if we need to go back and refactor+test properly.
  • Extreme edge cases trying to test with third party libraries where we don't have access to what we need.

In either of these cases, or in any situation where you're circumventing the access modifiers: You are going against how something was designed to be used. You should expect that this type of code will be extremely brittle due to changes.

I hope that helps! But please let me know if you have any questions!