Introduction

Reflection is a way to inspect and interact with types (classes, interfaces, methods, properties, etc.) at runtime. It lets your code look at other code, understand it, and even modify or invoke it without knowing about it at compile-time.

If you ever wanted to:

Then Reflection is what you need.

Why do we need Reflection?

Most of the time, you know which class you’re working with. But sometimes, your code needs to be dynamic. For example:

Reflection is powerful, but it should be used carefully because:

Where is Reflection defined?

Reflection lives in the System.Reflection namespace.

using System.Reflection;

Core Reflection Classes

Here are the most important classes you'll use:

Class Purpose
Type Represents type information (class, struct, interface, etc.)
MethodInfo Represents a method
PropertyInfo Represents a property
FieldInfo Represents a field
ConstructorInfo Represents a constructor
Assembly Represents a .NET assembly (DLL or EXE)

Getting Type Information using Type

You can get the type in three ways:

// 1. From an object
var type1 = myObject.GetType();

// 2. Using typeof
var type2 = typeof(MyClass);

// 3. From a string (late binding)
var type3 = Type.GetType("Namespace.MyClass");

Example. Get Properties of a Class

Type type = typeof(Person);
PropertyInfo[] properties = type.GetProperties();

foreach (var prop in properties)
{
    Console.WriteLine($"Property: {prop.Name}, Type: {prop.PropertyType}");
}

Example. Get Methods of a Class

MethodInfo[] methods = typeof(Person).GetMethods();

foreach (var method in methods)
{
    Console.WriteLine($"Method: {method.Name}");
}

Creating an Object at Runtime

You can create an object without using new by using Activator.

Type type = typeof(Person);
object obj = Activator.CreateInstance(type);

If the constructor needs parameters:

object obj2 = Activator.CreateInstance(type, "John", 25);

Invoking a Method by Name

Let’s say you want to call the SayHello method dynamically:

MethodInfo method = type.GetMethod("SayHello");
method.Invoke(obj, null);

If the method has parameters:

method.Invoke(obj, new object[] { "Hello" });

Accessing Fields and Properties

Getting and setting property value:

PropertyInfo prop = type.GetProperty("Name");

// Get value
var value = prop.GetValue(obj);

// Set value
prop.SetValue(obj, "Ravi");

Getting and setting field value:

FieldInfo field = type.GetField("age", BindingFlags.NonPublic | BindingFlags.Instance);

// Get value
var age = field.GetValue(obj);

// Set value
field.SetValue(obj, 30);

Note: For private fields, you must use BindingFlags.NonPublic and BindingFlags.Instance.

Working with Constructors

ConstructorInfo[] constructors = type.GetConstructors();

foreach (var ctor in constructors)
{
    Console.WriteLine($"Constructor: {ctor}");
}

You can also invoke constructors directly:

ConstructorInfo ctor = type.GetConstructor(new[] { typeof(string), typeof(int) });
object person = ctor.Invoke(new object[] { "John", 25 });

Loading an Assembly Dynamically

Assembly assembly = Assembly.LoadFrom("MyLibrary.dll");
Type[] types = assembly.GetTypes();

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

Binding Flags – Controlling What You See

By default, you only get public instance members. If you want to access private, static, etc., use BindingFlags.

BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
                     BindingFlags.Instance | BindingFlags.Static;

FieldInfo[] fields = type.GetFields(flags);

Real-world Example: Simple Logger using Reflection

public static void LogObjectProperties(object obj)
{
    Type type = obj.GetType();
    Console.WriteLine($"Logging: {type.Name}");

    foreach (var prop in type.GetProperties())
    {
        var value = prop.GetValue(obj);
        Console.WriteLine($"{prop.Name}: {value}");
    }
}

Call like this:

var person = new Person { Name = "Ravi", Age = 25 };
LogObjectProperties(person);

Risks of Using Reflection

Let’s be clear – Reflection is powerful, but:

Use it when you really need dynamic behavior. Otherwise, go with regular, strongly-typed code.

When to Use (and Avoid) Reflection

Use when

Avoid when

Summary