Understanding Reflection in C#

Introduction

Reflection is a powerful feature in C# that allows you to inspect and interact with object types and members at runtime. This capability can be especially useful for applications that need to dynamically interact with unknown objects, such as development tools, debugging utilities, and frameworks that need to discover type information at runtime.

What is Reflection?

Reflection in C# is part of the System.Reflection namespace and provides objects (of type Type) that describe assemblies, modules, and types. Using reflection, you can dynamically create instances of types, bind types to existing objects, or get the type from an existing object and invoke its methods or access its fields and properties.

Key Uses of Reflection

  1. Type Inspection: Discover information about assemblies, modules, types, methods, properties, and fields at runtime.
  2. Dynamic Invocation: Invoke methods or access fields and properties on objects dynamically.
  3. Late Binding: Create instances of types and invoke members without having compile-time knowledge of the types.
  4. Metadata Access: Access custom attributes and other metadata information applied to assemblies, types, methods, etc.

Basic Examples


Inspecting Types

To inspect a type at runtime, you can use the Type class. Here's how you can get information about a class:

using System;
using System.Reflection;

public class SampleClass
{
    public int Number { get; set; }
    public string Text { get; set; }

    public void PrintMessage()
    {
        Console.WriteLine("Hello from PrintMessage method!");
    }
}

class Program
{
    static void Main()
    {
        Type type = typeof(SampleClass);

        Console.WriteLine("Class Name: " + type.Name);
        Console.WriteLine("Namespace: " + type.Namespace);
        
        Console.WriteLine("\nProperties:");
        foreach (var prop in type.GetProperties())
        {
            Console.WriteLine(" - " + prop.Name);
        }

        Console.WriteLine("\nMethods:");
        foreach (var method in type.GetMethods())
        {
            Console.WriteLine(" - " + method.Name);
        }
    }
}

Dynamic Invocation

Reflection allows you to invoke methods dynamically, which can be useful when you do not know the methods at compile time:

using System;
using System.Reflection;

class Program
{
    static void Main()
    {
        Type type = typeof(SampleClass);
        object instance = Activator.CreateInstance(type);

        MethodInfo method = type.GetMethod("PrintMessage");
        method.Invoke(instance, null);
    }
}

Working with Fields and Properties

You can also get or set the value of fields and properties using reflection:

using System;
using System.Reflection;

public class SampleClass
{
    public int Number { get; set; }
    public string Text { get; set; }
}

class Program
{
    static void Main()
    {
        Type type = typeof(SampleClass);
        object instance = Activator.CreateInstance(type);

        PropertyInfo numberProp = type.GetProperty("Number");
        numberProp.SetValue(instance, 42);
        Console.WriteLine("Number: " + numberProp.GetValue(instance));

        PropertyInfo textProp = type.GetProperty("Text");
        textProp.SetValue(instance, "Hello, Reflection!");
        Console.WriteLine("Text: " + textProp.GetValue(instance));
    }
}

Accessing Custom Attributes

Reflection can also be used to access custom attributes applied to classes, methods, or properties:

using System;
using System.Reflection;

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class InfoAttribute : Attribute
{
    public string Message { get; }

    public InfoAttribute(string message)
    {
        Message = message;
    }
}

[Info("This is a sample class")]
public class SampleClass
{
    [Info("This is a sample method")]
    public void PrintMessage()
    {
        Console.WriteLine("Hello from PrintMessage method!");
    }
}

class Program
{
    static void Main()
    {
        Type type = typeof(SampleClass);
        InfoAttribute classAttribute = (InfoAttribute)Attribute.GetCustomAttribute(type, typeof(InfoAttribute));
        Console.WriteLine("Class Attribute Message: " + classAttribute.Message);

        MethodInfo method = type.GetMethod("PrintMessage");
        InfoAttribute methodAttribute = (InfoAttribute)Attribute.GetCustomAttribute(method, typeof(InfoAttribute));
        Console.WriteLine("Method Attribute Message: " + methodAttribute.Message);
    }
}

Conclusion

Reflection is a versatile tool in C# that provides runtime type information and dynamic capabilities. It enables developers to write more flexible and adaptable code by allowing them to interact with objects and their members dynamically. However, reflection should be used judiciously, as it can introduce performance overhead and reduce the clarity of the code. Proper understanding and application of reflection can significantly enhance the flexibility and power of your C# programs.


Similar Articles