How C# Reflection Works With Code Examples

By: Alexandra
  |  March 11, 2024
How C# Reflection Works With Code Examples

To write code that can read, examine and even write code in runtime. Sounds like magic? Welcome to the world of C# reflection.

Being able to write code that can examine and modify other pieces of code dynamically is quite a useful power. That’s what we call reflection, and in this post, you’ll learn how C# reflection works.

We’ll open the post by covering some fundamentals. What is reflection in C#? Why do people use it? We’ll break all that down for you in plain English. Then, we’ll examine a pressing question: is C# reflection slow?

After that, we’ll do justice to the “examples” part of the title: you’ll learn how to get started with C# reflection in practice. By the end of the post, you should have a solid understanding of the fundamentals of C# reflection and how you can write code that leverages its power.

Let’s jump right in and discover the world of C# reflection!

C# Reflection: The Fundamentals

As promised, let’s begin by covering the basics of C# reflection.

We call "reflection" the ability that some programming languages have to inspect their own constructs dynamically

What Is Reflection In C#?

We call “reflection” the ability that some programming languages have to inspect their own constructs dynamically. Using reflection, you can, for instance, load a class dynamically from an Assembly, test whether a given type has a specific member, and even create code dynamically.

To understand reflection in C#, there are a few basics you should understand about the hierarchy of its programming constructs:

  • Assemblies contain modules
  • Modules contain types
  • Types contain members

Why Is Reflection Used?

You need to use Reflection when you want to inspect the contents of an assembly. For example, you can get all members of the object by typing “.” before an object when viewing your Visual Studio editor IntelliSense.

A program reflects on itself when it extracts metadata from its assemblies, then uses it to modify its own behavior or inform the user. You can compare Reflection to C++RTTI (Runtime Type Information), except that it has a much wider swath of capabilities. When you write a C# program that uses reflection, you can use either the TypeOf operator or the GetType() method to get the object’s type.

Several important tools make use of reflection to enable their working. One example is unit test frameworks, which use reflection to identify test classes and methods marked with the necessary attributes.

Is Reflection In C# Slow?

Now, the million-dollar question: Is reflection slow in C#? The short answer is “yes.” Generally speaking, code that utilizes reflection is slower than code written in a conventional manner.

But is this a problem? Most of the time, it shouldn’t be. Reflection should be employed when the problem cannot be solved using traditional methods. Consequently, if you use reflection only in specific scenarios, your code should remain performant.

A Simple Use Case of C# Reflection

Reflection can be used to create applications called type browsers which allow users to select types and then read the data provided about them. This example illustrates how to use the static method GetType to find the Type of a variable:

// Using GetType to obtain type information:
int i = 42;
System.Type type = i.GetType();
System.Console.WriteLine(type);

The above example results in the following output:

System.Int32

Examples of Reflection in C#

Implementing reflection in C# requires a two-step process. You first get the “type” object, then use the type to browse members such as “methods” and “properties.”

This is how you would create instances of DateTime class from the system assembly:

// create instance of class DateTime
DateTime dateTime = (DateTime)Activator.CreateInstance(typeof(DateTime));

To access the sample class Calculator from Test.dll assembly, the Calculator class should be defined as the following:

namespace Test
{
    public class Calculator
    {
        public Calculator() { ... }
        private double _number;
        public double Number { get { ... } set { ... } }
        public void Clear() { ... }
        private void DoClear() { ... }
        public double Add(double number) { ... }
        public static double Pi { ... }
        public static double GetPi() { ... }
    }
}

Then, you can use reflection to load the Test.dll assembly:

// dynamically load assembly from file Test.dll
Assembly testAssembly = Assembly.LoadFile(@"c:\Test.dll");

To create an instance of the calculator class:

// get type of class Calculator from just loaded assembly
Type calcType = testAssembly.GetType("Test.Calculator");
// create instance of class Calculator
object calcInstance = Activator.CreateInstance(calcType);

And access its members (the following examples illustrate getting values for the public double Number property):

// get info about property: public double Number
PropertyInfo numberPropertyInfo = calcType.GetProperty("Number");
// get value of property: public double Number
double value = (double)numberPropertyInfo.GetValue(calcInstance, null);
// set value of property: public double Number
numberPropertyInfo.SetValue(calcInstance, 10.0, null);
The main class for reflection is the System.Type class, which is a partial abstract class representing a type in the Common Type System (CTS)

How Reflection in C# Works

The main class for reflection is the System.Type class, which is a partial abstract class representing a type in the Common Type System (CTS). When you use this class, you can find the types used in a module and namespace and also determine if a given type is a reference or value type. You can parse the corresponding metadata tables to look through these items:

  • Fields
  • Properties
  • Methods
  • Events

The System.Type class also comes with several instance methods you can use to get information from a specific type. Here’s a list of some of the most important ones:

  • GetConstructors() – gets the constructors for the type as an array of System.Reflection.ConstructorInfo.
  • GetMethods() – gets the methods for the type as an array of System.Reflection.MethodInfo.
  • GetMembers() – gets the members for the type as an array of System.Reflection.MemberInfo.

The System.Reflection namespace, as the name suggests, holds several useful classes if you want to work with reflection. Some of those are the three ones you’ve just read about. Here are some more important ones:

  • ParameterInfo
  • Assembly
  • AssemblyName
  • PropertyInfo

Late bindings can also be achieved through reflection. To illustrate, you might not know which assembly to load during compile time. In this instance, you can ask the user to enter the assembly name and type during run time so the application can load the appropriate assembly. With the System.Reflection.Assembly type, you can get three static types which allow you to load an assembly directly:

  • LoadFrom
  • LoadFrom
  • LoadWithPartialName

When you consider that an assembly is a logical DLL or EXE and a manifest is a detailed overview of an assembly, then it makes sense that a PE (portable executable) file for CTS would have the extension of .dll or .exe. Within the PE file is mainly metadata, which contains a variety of different tables such as a:

  • Filed definition table
  • Type definition table
  • Method definition table

When you parse these tables, you can retrieve an assembly’s types and attributes.

Uses for Reflection C#

There are several uses including:

  1. Use Module to get all global and non-global methods defined in the module.
  2. Use MethodInfo to look at information such as parameters, name, return type, access modifiers and implementation details.
  3. Use EventInfo to find out the event-handler data type, the name, declaring type and custom attributes.
  4. Use ConstructorInfo to get data on the parameters, access modifiers, and implementation details of a constructor.
  5. Use Assembly to load modules listed in the assembly manifest.
  6. Use PropertyInfo to get the declaring type, reflected type, data type, name and writable status of a property or to get and set property values.
  7. Use CustomAttributeData to find out information on custom attributes or to review attributes without having to create more instances.

Other uses for Reflection include constructing symbol tables, to determine which fields to persist and through serialization.

Additional Resources and Tutorials

For more information, including some helpful tutorials, visit the following resources:

At Stackify, we think C# and .NET Core will continue to be big in the near future, so brush up on your C# skills by checking out some of our other resources on topics such as .NET logging best practicesunderstanding and profiling C# sync await taskshow to find unhandled exceptionshow to convert a C# string to int, and more.

Improve Your Code with Retrace APM

Stackify's APM tools are used by thousands of .NET, Java, PHP, Node.js, Python, & Ruby developers all over the world.
Explore Retrace's product features to learn more.

Learn More

Want to contribute to the Stackify blog?

If you would like to be a guest contributor to the Stackify blog please reach out to [email protected]