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:
using System;
public class Program
{
public static void Main()
{
Type carType = typeof(Car);
Console.WriteLine($"Type Name: {carType.Name}");
MethodInfo[] methods = carType.GetMethods();
Console.WriteLine("Methods:");
foreach (MethodInfo method in methods)
{
Console.WriteLine($"- {method.Name}");
}
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:
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);
FieldInfo nameField = personType.GetField(
"_name",
BindingFlags.NonPublic | BindingFlags.Instance);
Console.WriteLine($"Field Name: {nameField.Name}");
PropertyInfo ageProperty = personType.GetProperty(
"Age"
BindingFlags.NonPublic | BindingFlags.Instance);
Console.WriteLine($"Property Name: {ageProperty.Name}");
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:
public class Person
{
public string Name { get; set; }
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.
Person person = new Person()
{
Name = "Dev Leader",
};
Type personType = typeof(Person);
PropertyInfo ageProperty = personType.GetProperty(
"Age",
BindingFlags.NonPublic | BindingFlags.Instance);
ageProperty.SetValue(person, 35);
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:
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.