Language: EN

csharp-reflexion

Reflection in C#

Reflection is the process by which a program can inspect and modify its own structure and behavior at runtime. In C#, reflection is implemented through the System.Reflection namespace.

With reflection, you can obtain information about assemblies, modules, types, methods, properties, fields, and events, and you can also invoke methods or access properties dynamically.

Obtaining information about variables and data types

One of the main utilities of reflection in C# is the ability to obtain information about the variables and data types used in our program. We can get details such as the variable name, its type, its current value, among others.

To achieve this, we can use the Type class in C#. This class allows us to access information about the data types used in our code.

An instance of Type can be obtained in several ways, such as using the typeof operator, the GetType method, or the static method Type.GetType.

int number = 10;
Type typeNumber = number.GetType();

In this example, we are obtaining the data type of the variable number and storing it in the variable typeNumber.

Now we can use Type to access the rest of the properties and elements of the class. I will provide a complete example to see it clearly 👇

using System;
using System.Reflection;

public class Example
{
    public int Field;
    public void Method() { }
}

public class Program
{
    public static void Main()
    {
        Type type = typeof(Example);
        Console.WriteLine("Type name: " + type.Name);

        FieldInfo[] fields = type.GetFields();
        foreach (var field in fields)
        {
            Console.WriteLine("Field: " + field.Name);
        }

        MethodInfo[] methods = type.GetMethods();
        foreach (var method in methods)
        {
            Console.WriteLine("Method: " + method.Name);
        }
    }
}

Modifying variables and data types

In addition to obtaining information, we can also use reflection to modify variables and data types at runtime. To access and modify properties, PropertyInfo is used.

For example, suppose we have a class Person with a property Name and we want to change its value at runtime. We can achieve this using reflection as follows:

Person person = new Person();
Type typePerson = person.GetType();

PropertyInfo propertyName = typePerson.GetProperty("Name");
propertyName.SetValue(person, "Luis");

This would be the person class we used in the example

public class Person
{
    public string Name { get; set; }
}

In this example,

  • We are obtaining the Name property of the Person class using reflection
  • Then, we use the SetValue() method to change its value to “Luis”.

Creating dynamic instances

Reflection allows us to create instances of dynamic types at runtime using Activator.CreateInstance.

Type typePerson = typeof(Person);
object instance = Activator.CreateInstance(typePerson);

PropertyInfo propertyName = typePerson.GetProperty("Name");
propertyName.SetValue(instance, "Luis");

Console.WriteLine("Name: " + propertyName.GetValue(instance));

Here,

  • We create an instance of Person at runtime
  • We set its Name property using reflection.

Invoking methods

To invoke methods dynamically, we use MethodInfo.

Type typeCalculator = typeof(Calculator);
object instance = Activator.CreateInstance(typeCalculator);

MethodInfo methodAdd = typeCalculator.GetMethod("Add");
object result = methodAdd.Invoke(instance, new object[] { 3, 5 });

Console.WriteLine("Result of Add: " + result);
public class Calculator
{
    public int Add(int a, int b)
    {
        return a + b;
    }
}

In this example, the Add method of the Calculator class is invoked dynamically, and the result is printed.

Loading assemblies at runtime

Reflection allows us to load assemblies at runtime and explore their types and members.

Assembly assembly = Assembly.Load("mscorlib");
Type[] types = assembly.GetTypes();

foreach (var type in types)
{
	Console.WriteLine("Type: " + type.Name);
}

This example loads the mscorlib assembly and lists all the types it contains.

Using custom attributes

Reflection allows us to work with custom attributes, being able to read or add metadata to elements at runtime.

Type type = typeof(MyClass);

if (type.GetCustomAttributes(typeof(MyAttribute), false).FirstOrDefault() is MyAttribute attributeClass)
{
	Console.WriteLine("Class description: " + attributeClass.Description);
}

MethodInfo method = type.GetMethod("ExampleMethod");
if (method.GetCustomAttributes(typeof(MyAttribute), false).FirstOrDefault() is MyAttribute attributeMethod)
{
	Console.WriteLine("Method description: " + attributeMethod.Description);
}
[Info("This is an example class.")]
public class MyClass
{
    [Info("This is an example method.")]
    public void ExampleMethod() { }
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class MyAttribute : Attribute
{
    public string Description { get; }

    public MyAttribute(string description)
    {
        Description = description;
    }
}

In this example,

  • Custom attributes are defined and used to provide descriptions to a class and a method
  • Those attributes are accessed at runtime using reflection

Reflection is a powerful and advanced feature that allows us to do things that would otherwise not be possible. However, in general, reflection is slow and complex.


Therefore, it should be used with caution and only when absolutely necessary.