DEV Community

Cover image for Coding Concepts - Reflection
Chris Bertrand
Chris Bertrand

Posted on • Updated on

Coding Concepts - Reflection

Reflection - What you need to know.

In computer science, reflection is the ability of a computer program to examine, introspect, and modify its own structure and behavior at runtime.[1]

So what does that mean? Reflection is a term thrown around every now and again and but do you really know what it means? Why and when it should be used, and what are its main strengths? It's a pretty difficult concept to grasp, but it's well worth the effort to learn as it can make certain seemingly impossible tasks possible.

Usually I run through examples in JavaScript to keep it understandable for most people, however reflection in JavaScript is not really the same as  in precompiled Object Oriented languages such as Java and C#, as it doesn't contain classes per se, so we'll be using examples from those today. The .Net Framework and Common Language Runtime (CLR) use reflection heavily for features such as Intellisense and other IDE features within Visual Studio as well as for serialisation so you'll probably be using reflection without even knowing about it.

Let's take a look at this example in C#.

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

As you would have guessed the output in the console is:

System.Int32

So this static method GetType uses reflection to obtain the type of the variable! Obviously when writing the code we know that "i" is an Integer but the runtime doesn't have this knowledge to hand, so it must search within itself to figure it out! Most people will have used GetType in the past, but some may have not known how it obtains the type!

Let's look at the main uses of Reflection and answer some of the questions raised above, I'll try and keep it easy to follow.

When to use reflection and why!

  • Traditionally used to load modules/classes from assembly and create an instance of them, at runtime.
  • For getting an Object's Public Attributes.
  • During testing, creating mock objects during runtime initialisation.
  • To create Generic libraries to handle different formats without redeployments, sometimes referred to, or using Implicit Late Binding.
  • When building new types at runtime.
  • For examining and instantiating types in an assembly.
  • The ability to change the value of a field marked private in a 3rd party library.
The ability to inspect the code in the system and see object types is not reflection, but rather Type Introspection. Reflection is then the ability to make modifications at runtime by making use of introspection. The distinction is necessary here as some languages support introspection, but do not support reflection. One such example is C++

So as you can see it's mainly about classes, looking at them, changing them, instantiating them, but all at runtime rather than compile time!

Compile Time Vs Runtime

The best way I can explain the difference between the two is by looking at your running shoes!

Compile time is like doing up your shoe laces and checking them before you go out for a run. Whatever you do to your shoes will be saved and kept. This will give you an insight whether anything is wrong with them, and what they contain and can do.

Runtime is when you're already out on the road! Your shoes have already been prepared for you, you can't usually change those shoes or retie those laces unless you stop, but you can see what the shoes are capable of, and use any existing features that these shoes have available! You could switch shoes by jumping into a new set, but this requires the new set of shoes to be already created too and available to you on the run.

In object-oriented programming languages, reflection allows inspection of classes, interfaces, fields and methods at runtime without knowing the names of the interfaces, fields, methods at compile time. It also allows instantiation of new objects and invocation of methods.

So above we had an example of using reflection on an object and getting the object attributes, now lets looks at using reflection to get info from a Type, and how we'd find and load new assemblies during runtime.

        // Using Reflection to get information from an Assembly:  
        System.Reflection.Assembly integerTypeAssembly = typeof(System.Int32).Assembly;  
        System.Type integerType = typeof(System.Int32);

        System.Console.WriteLine(integerTypeAssembly); // mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
        System.Console.WriteLine(integerType.ToString()); // System.Int32

        //Use this typeString to refind the type
        Type calcType = integerTypeAssembly.GetType(integerType.ToString());
        System.Console.WriteLine(calcType); // System.Int32

        // We can then Create a new Instance of whatever this type may be, and call it's methods.
        object integerInstance = Activator.CreateInstance(calcType); 
        // In this case it's just a boring Integer, and we can see it's been initialised to it's default of 0..
        System.Console.WriteLine(integerInstance.ToString());
Enter fullscreen mode Exit fullscreen mode

We can see the nuanced difference of looking at a variable that was set during compilation, and querying the library itself, and the different ways we can use these two types of reflection to make changes to the system during runtime.

A Real World Example

A useful real world example of using reflection would be switching between assemblies based on a value stored in a database or other static resource. For example: you have "GoogleSearchService" and "BingSearchService" configured in your system. Usually you would hard code/inject one of these services as the one to be used.

But say for instance you had a "LoadSearchServiceAssemblyFromResource()" method that retrieved the service from your database which would then be used at runtime.

If this service was to go down, become obsolete, or your contract was to be terminated, rather than having to redeploy your system using "BingSearchService", you would simply update your database/storage field pointing to your other assembly("BingSearchServiceAssembly").

The next time your Search Service was called, it would switch dynamically at runtime to your new Service. This for me is the  major benefit of reflection and why it can or should be used. As each service is a dll you can call them directly using reflection using a format such as this.

//This will load the dll from a static resource such as a DB or File
Assembly searchAssembly = LoadSearchServiceAssemblyFromResource();
// Now we need to find the class in the assembly, this in this instance is simply called "Search"
Type searchType = searchAssembly.GetType(searchAssembly.GetName().Name + "Search");

// If we have found the class
if (searchType != null)
{
    object searchResult = null;
    dynamic classInstance = Activator.CreateInstance(searchType);
    // DoSearch is a method that is declared on both SearchService Classes!
    var searchResult = instance.DoSearch();
}
Enter fullscreen mode Exit fullscreen mode

You may not always have the scenario to use it, but knowing when and why you should is invaluable.

There's load more to Reflection that hasn't been covered here. So have a look at the additional reading if you want to read more on the topic.


Additional Reading

Microsoft Concept Docs - Reflection

Type Introspection and Reflection

Microsoft - Reflections and CodeDom

Microsoft Reflection - Dynamically Loading and Using Types

StackOverflow - What is reflection and why is it useful

Oldest comments (11)

Collapse
 
kayis profile image
K

Good writeup :)

After using reflection in Java and PHP I had the impression that JavaScript is even better in that way, because classes are implemented dynamically and can be accessed without extra magic, almost homoiconic.

Collapse
 
chris_bertrand profile image
Chris Bertrand

JavaScript and reflection is an interesting concept, as JavaScript doesnt really have the notion of classes,as everything is an object and already being a dynamic language things get a bit murky.

But ES5 and more so ES6 do contain a Reflection Api. This great article goes way more in depth on the topic then i ever could: ponyfoo.com/articles/es6-reflectio...

Collapse
 
nans profile image
Nans Dumortier

Thanks Chris for the reference to ponyfoo.com ! I didn't know that website, and will definitely hang out there more often !

Thread Thread
 
chris_bertrand profile image
Chris Bertrand

It's great right! Looks like it's had a visual overhaul since I posted this too! Looks even better now.

Thread Thread
 
nans profile image
Nans Dumortier

Yup, and it's a PWA too so I feel even better browsing it 😁

Collapse
 
jude00861082 profile image
Jude

Nice IDE themes 😍
Where can I get it?
.
Thanks

Collapse
 
chris_bertrand profile image
Chris Bertrand

Thanks Jude, unfortunately it's just the default markdown stylings. But i do agree it does look good! This guide is pretty cool for learning more about how it works guides.github.com/features/masteri...

Collapse
 
usmansabir profile image
Usman Sabir

2nd code example doesn't work

// Using Reflection to get information from an Assembly:

System.Reflection.Assembly integerTypeAssembly = typeof(System.Int32).Assembly;

System.Console.WriteLine(integerTypeAssembly); // mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

// We can then Create a new Instance of whatever this type may be, and call it's methods.
object integerInstance = Activator.CreateInstance(integerTypeAssembly);
// Now we can use integerInstance as if it was an Intger Type, calling its MaxCValue function.
System.Console.WriteLine(integerInstance.MaxValue());

Collapse
 
chris_bertrand profile image
Chris Bertrand

Hey Usman,

You're very much correct, I should of tested the snippet in .Net Fiddle before posting it. I wrote is as pseudo code, but can see how it could be misinterpreted. I've updated the example with one that actually works. Although the Integer class is a very boring example!

Collapse
 
rafalpienkowski profile image
Rafal Pienkowski

Nice article Chris. Personally, I try to avoid reflection as long as it's possible. As you said, reflection is being resolved at runtime and if I made a mistake in the source code I'll know about it when I run my program on the test, UAT or production environment (this is pretty late in my opinion).
I like your real life example. I think it's very descriptive. If I have to face such a problem I'd like to use such kind of dynamic dependency injection with a configuration provided from a file or a database.
I don't want to say that reflection is an evil but we should use it very carefully because it's a two-edged sword.

Once again great post. Cheers.

Collapse
 
chris_bertrand profile image
Chris Bertrand

Thanks Rafal!