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.

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

You can obtain an instance of Type in various ways, such as using the typeof operator, the GetType method, or the static method Type.GetType.

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

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

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

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, let’s say we have a Person class with a Name property and we want to change its value at runtime. We can achieve this using reflection as follows:

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

PropertyInfo nameProperty = personType.GetProperty("Name");
nameProperty.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 you to create instances of dynamic types at runtime using Activator.CreateInstance.

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

PropertyInfo nameProperty = personType.GetProperty("Name");
nameProperty.SetValue(instance, "Luis");

Console.WriteLine("Name: " + nameProperty.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 utilize MethodInfo.

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

MethodInfo addMethod = calculatorType.GetMethod("Add");
object result = addMethod.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 you 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 you 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 classAttribute)
{
	Console.WriteLine("Class description: " + classAttribute.Description);
}

MethodInfo method = type.GetMethod("ExampleMethod");
if (method.GetCustomAttributes(typeof(MyAttribute), false).FirstOrDefault() is MyAttribute methodAttribute)
{
	Console.WriteLine("Method description: " + methodAttribute.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.
  • These attributes are accessed at runtime using reflection.

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


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