Introduction to Reflection in C#

Last Updated : 21 Oct, 2025

Reflection in C# is a mechanism that allows a program to inspect metadata and interact with types at runtime. It enables developers to discover information about assemblies, modules, types, methods, properties and other members dynamically.

Reflection is part of the System.Reflection namespace and is commonly used for dynamic type creation, late binding and code analysis.

Namespace and Assembly

  • Namespace: System.Reflection
  • Assembly: mscorlib.dll or System.Runtime.dll (depending on .NET version)

Key Points

  • Allows runtime inspection of types, methods, fields and properties.
  • Enables dynamic invocation of members.
  • Used by frameworks for serialization, dependency injection, ORM mapping and unit testing.
  • Works with metadata that the compiler embeds in assemblies.
  • Requires caution due to performance overhead and reduced type safety.

Why Use Reflection

  • To create and use objects without knowing their types at compile time.
  • To access attributes applied to code elements.
  • To examine assemblies for plugins or dynamically loaded modules.
  • To inspect method parameters, return types and visibility modifiers.

Reflection should be used only when necessary. For frequent type inspection or invocation, prefer compile-time constructs like generics or interfaces, as they are safer and faster.

Basic Example

C#
using System;
using System.Reflection;

class Person
{
    public string Name { get; set; }
    public void SayHello() => Console.WriteLine($"Hello, my name is {Name}");
}

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

        Console.WriteLine($"Type Name: {type.Name}");
        Console.WriteLine("Properties:");
        foreach (var prop in type.GetProperties())
            Console.WriteLine($"- {prop.Name}");

        Console.WriteLine("Methods:");
        foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
            Console.WriteLine($"- {method.Name}");
    }
}
  • typeof(Person) retrieves metadata about the Person class.
  • GetProperties() and GetMethods() are used to list public properties and methods.
  • The program dynamically explores the class structure at runtime.

Loading Assemblies Dynamically

Reflection allows you to load assemblies at runtime using the Assembly class.

C#
using System;
using System.Reflection;

class Program
{
    static void Main()
    {
        Assembly assembly = Assembly.Load("System.Text.Json");
        Console.WriteLine($"Assembly: {assembly.FullName}");

        foreach (Type t in assembly.GetTypes())
            Console.WriteLine($"Type: {t.FullName}");
    }
}

This code dynamically loads the System.Text.Json assembly and displays all available types defined in it.

Creating Objects Using Reflection

Objects can be created dynamically without knowing their exact type at compile time using Activator.CreateInstance().

C#
using System;

class Person
{
    public string Name { get; set; } = "Alex";
    public void Greet() => Console.WriteLine($"Hello, I am {Name}");
}

class Program
{
    static void Main()
    {
        Type type = typeof(Person);
        object obj = Activator.CreateInstance(type);
        type.GetMethod("Greet")?.Invoke(obj, null);
    }
}
  • Activator.CreateInstance() creates an instance dynamically.
  • The Greet() method is invoked through reflection, demonstrating late binding.

Accessing Fields and Properties

Reflection allows reading or writing member values dynamically.

C#
using System;
using System.Reflection;

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

class Program
{
    static void Main()
    {
        Student student = new Student();
        Type type = student.GetType();
        PropertyInfo prop = type.GetProperty("Name");

        prop.SetValue(student, "John");
        Console.WriteLine(prop.GetValue(student));
    }
}

Here, property Name is accessed and modified dynamically using GetProperty(), SetValue() and GetValue().

Using Reflection with Attributes

Reflection is essential for reading custom attributes applied to code elements.

C#
using System;
using System.Reflection;

[AttributeUsage(AttributeTargets.Class)]
class DeveloperAttribute : Attribute
{
    public string DeveloperName { get; }
    public DeveloperAttribute(string name) => DeveloperName = name;
}

[Developer("Geek")]
class Project {}

class Program
{
    static void Main()
    {
        Type type = typeof(Project);
        object[] attrs = type.GetCustomAttributes(false);

        foreach (var attr in attrs)
        {
            if (attr is DeveloperAttribute devAttr)
                Console.WriteLine($"Developer: {devAttr.DeveloperName}");
        }
    }
}

This example retrieves metadata about a custom attribute applied to a class, demonstrating how reflection reads declarative information.

Commonly Used Reflection Classes

ClassDescription
TypeProvides information about class metadata such as methods, fields and properties.
AssemblyRepresents an assembly and provides methods to load and examine it.
MethodInfoRepresents method metadata and allows dynamic invocation.
PropertyInfoRepresents property metadata and provides access to property values.
FieldInfoRepresents a field and provides methods to get or set its value.
ConstructorInfoProvides access to constructor metadata and allows instance creation.
ParameterInfoDescribes parameters of a method or constructor.

Advantages

  • Enables dynamic type discovery and method invocation.
  • Allows working with types not known at compile time.
  • Useful for frameworks, tools and libraries requiring runtime type analysis.

Limitations

  • Performance overhead due to runtime inspection.
  • Security concerns if used to access private members.
  • Reduced readability and compile-time safety.
Comment

Explore