Skip to main content
.NET

Learn To Understand Reflection in .NET

Reflection is used to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object. In this tutorial about reflection in .NET I will break it down into human-readable content with examples.

Christian Schou

How to use reflection in .NET? It’s a question many new developers are asking them self and I totally get that, I did that myself at the beginning of my programming career. When you are done reading this article, you will be able to define what reflection in .NET is and how you can utilize it. You will also be able to tell the difference between System.Type and type(s). We will cover a few practical examples to make it easier to understand how we can use reflection to get the Type of an object or a type. We will also cover how to interact with Type objects and how to access custom attributes.

I have tried to “convert” the official documentation about reflection in .NET to a more “human-readable” article. If you take a look below you can see a short description of what .NET reflection is and its roadmap.

If you are ready, then let’s get started and learn how we can use reflection in .NET.

What is Reflection in .NET?

Reflection is a way for developers to get System.Type instances. These instances are then used to describe assemblies, types, and modules. We can even use an instance to invoke a method and access the variables of its target objects. In other words – reflection gives you the option to use code that was not available at compile time.

Reflection can be used to find all the types in an assembly and then invoke the methods inside that assembly. This gives us the option to dynamically create an instance of a type, and bind that type to an existing object. Another option is to get the type from another already existing object and invoke its methods or access its fields and properties. Reflection also gives us the option to access the attributes of our objects and their data. In other words, Reflection in .NET and other programming languages is a powerful tool when we don’t know much about an assembly we would like to integrate with.

Reflection Roadmap

System.Type System.Reflection
Assembly
GetType() Module
InvokeMember() AssemblyName
GetInterface(), GetInterfaces() InterfaceInfo
GetContructor(), GetConstructors() ConstructorInfo
FindMembers() ParameterInfo
GetEvent(), GetEvents() EventInfo
GetMember(), GetMembers() MemberInfo
GetMethod(), GetMethods() MethodInfo
GetField(), GetFields() FieldInfo
GetProperty(), GetProperties() PropertyInfo

The class System.Type and namespace System.Reflection got a very important role when talking about Reflection in .NET. They work in close collaboration and are the ways we achieve reflection inside our application. Above is a table showing how they are related.

An introduction to System.Reflection

System.Reflection is a namespace and it contains classes and interfaces. These provide a way to get a managed view of fields, methods, and types as well as the option for us to invoke the types dynamically.

The process described above is what we know as reflection in .NET. In the table above you will see some of the classes marked with bold text. This is because they are the most used classes and I have included a short description of each below, for your reference.

Assembly

This of course represents an assembly. An assembly is a self-describing, versionable, and reusable component of a common language when it’s running (also named runtime). The assembly class will contain a number of methods allowing you to load, investigate and manipulate the assembly.

Module

We can use this class to perform reflection on a module when we access the module inside the assembly.

AssemblyName

The assembly name is responsible for allowing us to get information about the assembly. These could be values like:

  • The supported culture.
  • Versioning.
  • Naming.
  • Cryptographic key pair.

ParameterInfo

ParameterInfo is used to discover the attributes of a parameter and provide access to the metadata for the given parameter. You can use an instance of ParameterInfo to obtain information about the data type, default value, and so on for the parameter, you are working with. If you call GetParameters you will get an array of ParameterInfo objects representing the parameters of a method.

MethodBase.GetParameters Method (System.Reflection)
When overridden in a derived class, gets the parameters of the specified method or constructor.

EventInfo

The class EventInfo is used to contain information for a given event. We can use this class to discover the attributes of an event and provide access to the event metadata. I typically use this class to inspect events and bind my event handlers.

MemberInfo

MemberInfo is an abstract base class for classes used to obtain information about all attributes of a member/a class. Here I am talking about:

  • Fields.
  • Properties.
  • Constructors.
  • Methods.
  • Events.

MemberInfo introduces the basic functionality that all members provide.

MethodInfo

MemberInfo is used to discover the attributes of a method and provides access to method metadata. The MethodInfo class represents a method of a type. You can use a MethodInfo object to obtain information about the method that the object represents and to invoke the method.

MethodInfo Class (System.Reflection)
Discovers the attributes of a method and provides access to method metadata.

FieldInfo

Fields are variables we define in a class. FieldInfo is providing us access to the metadata for a given field within the class and provides a dynamic set and get functionality for the field we are adding. The class will not be loaded into the memory at runtime until it is invoked or get is called onto the object.

PropertyInfo

A property is logically the same as a field. A property is a named aspect of an object’s state that can be obtained through get and set accessors on the object. A property may be read-only, in which case the set functionality is not supported at runtime.

PropertyInfo Class (System.Reflection)
Discovers the attributes of a property and provides access to property metadata.

What is the difference between System.Type and type?

Before we begin to look at some code, I think it Is important to be clear about what the difference between System.Type and type is.

According to the official documentation from Microsoft about C# types, each variable or constant in C# has a type. A type could be a string, int, float, double, etc… you get the point. Each method is capable of accepting and returning parameters and values known as type.

The C# type system
Learn about creating types in C#, such as tuples, records, value types, and reference types.

You can find several categories of type. Most common are the built-in types: string, int, bool, double, etc… you can also use value types (struct and enums), and reference types (classes, interfaces, deletages, and records). System.Type is responsible for providing us with methods so that we can reflect on the objects, variables, and constants – regardless of their type. There you got the difference.

Now let’s move on to the part you have been waiting for – the code.

Working with System.Type

When we would like to retrieve the object of System.Type, we can get it either of a type or an object. Below are two examples showing you how you can obtain System.Type from both of them.

Get System.Type from an object

When you would like to get System.Type on an object, you can call the method GetType() on that specific object. Below is a demo class where I call GetType() to get the type of the object.

namespace SystemTypeDemo;
  
public class Demo {
    public static void Main(string[] args) {
        Demo demo = new(); // Create new instance of the object
    
        Type demoType = demo.GetType(); // Get the type of the object
    
        Console.WriteLine(demoType); // Print it our to the console
        // SystemTypeDemo.Demo
    }
}

When you define a new variable of type var, we can use System.Type to get the type when it is being inferred at compile time.

var x = 26;
 
Console.WriteLine(x.GetType());
// System.Int32

Get System.Type from a type

If we want to get the System.Type instance of a type, we can make use of typeof.

Below is an example of how you can get the type of an instance.

namespace SystemTypeDemo;

public class Demo {
    public static void Main(string[] args) {
        Type demoType = typeof(Demo);
      
        Console.WriteLine(demoType);
        // SystemTypeDemo.Demo
    }
}

What is the difference between GetType and typeof?

You are now able to use two different methods to obtain the System.Type instance on an object and a type. But have you ever wondered what the core difference is between the two? Let’s take a deeper look at how they differentiate from each other.

The primary difference between the two are listed below for your reference.

  1. .GetType() is executed at run time, while typeof is executed at compile time.
  2. .GetType() is only used to get System.Type of an object instance, while typeof returns System.Type of a type.

When to use reflection in .NET?

Right now you are able to make use of reflection in .NET to get the System.Type instance of an object or type. You are probably wondering – okay Christian, what can I use reflection for in my daily life? What can I achieve using reflection in my application(s)?

Earlier in this article, I listed a few different classes and methods for reflection in the roadmap section. Let’s take a look at how we can use reflection with assemblies, arguments, and attributes. These are some of the most common use cases for reflection in C#, so let’s have a look at some quick examples to give you an understanding of how you can use this in your own apps.

How to get information from assemblies?

One thing I often do when using reflection in C# is retrieve information about a particular assembly. This is done like below, where we retrieve the assembly that contains the Int32 type and displays its name and file location.

using System;
using System.Reflection;

public class Example
{
    public static void Main()
    {
        // Get a Type object.
        Type t = typeof(int);

        // Instantiate an Assembly class to the assembly housing the Integer type.
        Assembly assem = Assembly.GetAssembly(t);

        // Display the name of the assembly.
        Console.WriteLine("Name: {0}", assem.FullName);

        // Get the location of the assembly using the file: protocol.
        Console.WriteLine("CodeBase: {0}", assem.CodeBase);
    }
}

// The example displays output like the following:
//    Name: mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
//    CodeBase: file:///C:/Windows/Microsoft.NET/Framework64/v4.0.30319/mscorlib.dll

Doing the above is equivalent to retrieving the value of the Type.Assembly property and I would actually recommend using Type.Assembly as that property is much faster in terms of performance.

In order to do the above, you must have a Type object. This means that the assembly in which the class is defined must already be loaded in order to call the GetAssembly() method. You could also do the following: Console.WriteLine(typeof(int).Assembly);.

How to know an object’s actual Type?

When you want a more generic/dynamic way of returning variables without having to create huge tuples, we can use object-typed variables. However, that comes with a cost… you won’t be able to access the methods, variables, and properties.

namespace SystemTypeDemo;
 
public class Dog {
    public Dog(string name) {
        Name = name;
    }
    
    public string Name { get; }
    
    public void Bark() {
        Console.WriteLine($"Wuf wuf, I am {Name}! Can I have a treat?");
    }
}
  
public class Demo {
    public static void Main(string[] args) {
        object kenya = new Dog("Kenya");
        Console.WriteLine(kenya.Name);
    }
}

If I ran a build for this code, I would end up with a compiler error, like this: CS1061.

CS1061: 'object' does not contain a definition for 'Name' and no accessible extension method 'name' accepting a first argument of type 'type' could be found (are you missing a using directive or an assembly reference?).

I could go the easy way and cast my object-typed variable into the type that I would like to use it with. But we got reflection – so let’s use it. We can actually retrieve the System.Type object and interact with it to get the result we want.

public class Demo {

    public static void Main(string[] args) {

        object kenya = new Dog("Kenya"); // Kenya is my dog
 
        Type kenyaType = kenya.GetType();
 
        // Get the property and method info from the Type "kenyaType"
        PropertyInfo kenyaNameProperty = kenyaType.GetProperty("Name");
        MethodInfo methodInfoProperty = kenyaType.GetMethod("Bark");
     
        // Retrieve the value or invoke the method on an instance  
        Console.WriteLine($"From {kenyaNameProp?.GetValue(kenya)}");
        methodInfoProp?.Invoke(kenya, new object[] { });

    }

}

What happens in the code above?

  1. First, we create a new instance of an object of a type Dog with the name Kenya.
  2. Then we get the property and method info and store those into a variable each. In both cases, we needed to pass a reference of the instance from which we obtained the Type (our object kenya).
  3. Then we print our to the console and invoke the method property.

How to get an object’s Type Arguments?

For this example, I will be creating a Dictionary containing a string and double to hold the name and age of dogs.

Dictionary dogs = new() { { "Kenya", 1.5 } };
 
Type dogTypes = dogs.GetType();

To get the Type arguments supplied in our dog dictionary, we can call GetGenericArguments() to store the Type arguments inside an array and then print each type in the console using a for each loop.

Type[] typeArguments = dogTypes.GetGenericArguments(); // Store the type arguments in an array

// print each type argument in the console
foreach (Type typeParameter in typeArguments)
{
    Console.WriteLine($"Type Argument is of Type: {typeParameter}");
}

// Type Argument is of Type: System.String
// Type Argument is of Type: System.Double

Awesome! We now got a way to get the Type arguments from a dictionary, etc… as you can see we got the two variable types printed as we expected.

How to use reflection to get data from an attribute?

If we would like to get the data stored inside an attribute by using reflection, we can call the method GetCustomAttribute() onto the attribute. Let’s take a new example with my dog.

To get the data stored inside an attribute, we can utilize reflection again, let’s see how we can do this on a custom attribute named OriginCountry.

public class OriginCountryAttribute : Attribute
{
    public string originCountry;
 
    public OriginCountryAttribute(string originCountry)
    {
        this.originCountry = originCountry;
    }
}

Let’s use this new attribute on the Dog class we created/used in the previous example. It looked like this:

public class Dog {
    public Dog(string name) {
        Name = name;
    }
    
    public string Name { get; }
    
    public void Bark() {
        Console.WriteLine($"Wuf wuf, I am {Name}! Can I have a treat?");
    }
}

Now let’s use reflection in .NET to retrieve the data from our newly created attribute named OriginCountry, just like I have done below:

[OriginCountry("French")]
public class Dog
{
    public Dog(string name) {
        Name = name;
    }
    
    public string Name { get; }
    
    Type thisType = this.GetType();
 
    Attribute _attribute = thisType.GetCustomAttribute(
        typeof(OriginCountryAttribute));
 
    OriginCountryAttribute originCtryAttr_ = (OriginCountryAttribute)_attribute;

    public void Bark() {
        Console.WriteLine($"Wuf wuf, I am {Name}! Can I have a treat? I am originally from {originCtryAttr_?.originCountry}");
    }
}

What happens in the code above?

  1. First we the System.Type value from our Dog object.
  2. Then we use reflection to get the attribute OriginCountryAttribute attached to the Dog class.
  3. Finally, we ended up casting the value of the attribute type into OriginCountryAttribute so we are able to interact with the attribute in our Console.Writeline() statement.

Please note that the method GetCustomAttribute() only returns the type of the attribute and not the actual type passed to it.

If you were to show all attributes of an object, you could do this easily using the method GetCustomAttributes() on a Type. Just like I have shown below:

Type dogType = typeof(Dog);
 
foreach (Attribute attr in Attribute.GetCustomAttributes(dogType))
{
    Console.WriteLine($"Attribute: {attr}");
}

That is how easily you can get all the attributes from a Type.

Summary

In this article, we covered reflection in .NET and its roadmap. You should now be able to use reflection in your C# projects/applications. Reflection is not a topic many teachers are talking about. It’s a huge topic that easily could confuse a lot of especially new programmers. It took me a while to get an understanding of the reflection concept.

Reflection is really useful and can be applied in many different ways – how is totally up to you. You could try to make a demo console application and try out the C# reflection examples I have given you in this article.

If you got any questions, please let me know in the comments. Until next time – happy coding.