Making reflection in .NET Core work faster
Image from Unsplash

Making reflection in .NET Core work faster

Techniques for optimizing reflection in C#

Reflection allows accessing type structure and its meta-data in runtime. Using reflection, you can dynamically instantiate objects, access fields, methods and properties regardless of the protection level. Without reflection you could only access properties with appropriate access level but with reflection, you have no problem accessing even private elements of the class. Unfortunately, this ability comes at great cost.

Using reflection can significantly lower down your performances. If you have fewer objects accessed with reflection you probably won't notice the execution speed of your code, but if you have higher load, especially if you have large collections and you are executing reflection in a loop, your application performances will be significantly lowered and you will notice the execution speed increases.

The best advice for the reflection usage is do not use it! There are other ways to access properties and methods of the objects such as interfaces and abstract classes. It is easier to say than do it, sometimes you need to access objects dynamically. You may not know the type or instance do not have the same base class or they just do not implement the same interface. This is common for the mapping objects and transforming them from one type to another.

Pretty much all mapping libraries you can find for .NET are relying on reflection. This is because they are generic type mappers and are supposed to work for any type and object instances, so they need reflection to discover source and target objects types.

Even though reflection is heavy and expensive operation, there are techniques to lower down the impact and increase the speed of reflection usage in your code. Here are some of them which will definitely help you reduce the reflection downsides related to the speed.

Cache your reflection results

Simplest but the most powerful thing you can do is caching the reflection results. You already know reflection is slow, so try not to repeat it in your code. Pretty much always result of the reflection is type related (System.Reflection.PropertyInfo or System.Reflection.MethodInfo instance). I the following example you will see how you should not use the reflection and what is the impact of not caching reflection results.

I will use simple POCO class named person with a single property called Name.

    public class Person
    {
        public String Name { get; set; }
    }
    

Now to see the read difference we will instantiate Person class 1000000 times in a regular way using new keyword, then with reflection used in every loop step and compare.

        private static void RegularConstructor()
        {
            for (int i = 0; i < 1000000; i  )
            {
                var instance = new Person();
            }
        }
    

Let's see how we would instantiate constructor of the Person class using reflection

private static void ReflectionConstructor()
        {
            for (int i = 0; i < 1000000; i  )
            {
                var instance = typeof(Person).GetConstructor(new Type[] { }).Invoke(new object[] { });
            }
        }
    

If we run these two methods, there will be significant difference in the time spent to perform the same outcome. For the benchmark purpose I wrote a simple generic class that will execute the method passed and return the time taken for the method to complete.

        private static long MeasureExecTime(Action action)
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();
            action();
            watch.Stop();
            return watch.ElapsedMilliseconds;
        }
    

All we have to do now is to run these two constructor test methods through our benchmark method and compare the results

        static void Main(string[] args)
        {
            Console.WriteLine($"Regular constructor:\t{MeasureExecTime(RegularConstructor)}");
            Console.WriteLine($"Reflection constructor:\t{MeasureExecTime(ReflectionConstructor)}");

            Console.ReadKey();
        }
    

And the results are..

Regular constructor:    14
Reflection constructor: 236

It is clear that reflection is killing our performances. We did not cache our result which is typeof(Person). What we did is we called it over and over in the loop. Now let's see the result of the following slightly modified code.

        private static void ReflectionConstructor()
        {
            var constructor = typeof(Person).GetConstructor(new Type[] { });
            for (int i = 0; i < 1000000; i  )
            {
                var instance = constructor.Invoke(new object[] { });
            }
        }
    

This code now executed gives a lot lower time spent for reflection code to be executed

Regular constructor:    13
Reflection constructor: 163

It is clear that the time taken is reduced by more than 50% comparing to the previous run, but we are still far away from regular constructor code speed. The time taken is still 10 times longer than with simple new keyword usage. Let's see what we can to speed up constructing instances of our test POCO.

Improving constructor invocation with Activator and Expressions

Regarding the constructor invocation and creating new instances dynamically from the runtime, apart from pure reflection we have two more options. The first one is using System.Activator class. 

        private static void ActivatorConstructor()
        {
            var type = typeof(Person);
            for (int i = 0; i < 1000000; i++)
            {
                var instance = Activator.CreateInstance(type);
            }
        }
    

It is a lot more convenient to use Activator comparing to reflection in terms of coding, but it is also a lot faster when it comes to executing part. Let's see one more option for dynamic object constructing and we'll eventually compare the results and get the winner.

        private static void ExpressionConstructor()
        {
            var expression = Expression.Lambda<Func<Person>>(Expression.New(typeof(Person))).Compile();
            for (int i = 0; i < 1000000; i++)
            {
                var instance = expression();
            }
        }
    

Expressions are another way for dynamically accessing type properties and methods. The downside of expressions in C# is that compiling the expression takes time, so same caching rule applies to expression compiling. Once you compile the expression, tend to re-use it in code instead compiling new expressions over and over.

We have four options now for dynamically creating class instances, so let's run them through our benchamark method and compare the speed:

        static void Main(string[] args)
        {
            Console.WriteLine($"Regular constructor:\t{MeasureExecTime(RegularConstructor)}");
            Console.WriteLine($"Reflection constructor:\t{MeasureExecTime(ReflectionConstructor)}");
            Console.WriteLine($"Activator constructor:\t{MeasureExecTime(ActivatorConstructor)}");
            Console.WriteLine($"Expression constructor:\t{MeasureExecTime(ExpressionConstructor)}");

            Console.ReadKey();
        }

    

The result is the following

Regular constructor:      14
Reflection constructor:   159
Activator constructor:    61
Expression constructor:   74

 Constructor

Improving property access

Another common access to object instance dynamically, apart from constructors during the runtime is access to object properties. As I mentioned before, this is often done in scenarios when data mapping is done from one object to another object. 

As with constructors, the fastest way is to invoke the property getter and setter directly on the object type, but this only applies when the type of the object is known during compile time. If you need to access the object instance during the runtime and you are discovering the object instance type during the runtime than most logical option is to go with reflection. As I mentioned before this can cause performance downgrade as reflection calls are considered as heavy operations.

Since each property consists of Get and Set methods, we'll do both setter and getter property method performance comparison using different methods to invoke them. Let's first see how can we access getter methods.

Accessing property getter method

The following three methods are accessing the Person object instance using different techniques:

        private static void RegularGet()
        {
            var instance = new Person();
            for (int i = 0; i < 1000000; i++)
            {
                var value = instance.Name;
            }
        }

        private static void ReflectionGet()
        {
            var instance = new Person();
            var type = instance.GetType();
            for (int i = 0; i < 1000000; i++)
            {
                var value = type.GetProperty("Name").GetValue(instance);
            }
        }

        private static void ExpressionGet()
        {
            var instance = new Person();
            var type = instance.GetType();
            var instanceParam = Expression.Parameter(type);

            var expression = Expression.Lambda<Func<Person, Object>>(
                          Expression.Convert(
                              Expression.Call(instanceParam, type.GetProperty("Name").GetGetMethod()),
                              typeof(Object)
                          ),
                        instanceParam).Compile();
            for (int i = 0; i < 1000000; i++)
            {
                var value = expression(instance);
            }
        }
    

Of course, the execution time for the first way of accessing the property Get method will be the fastest as the access code is defined during the compile time. Although it is the fastest one, it is not the one we need as it is directly bound to the type person. It wont work for any other unrelated type with the same property name, so we focus on the second two.

Regular Get:            5
Reflection Get:         224
Expression Get:         89

Reflection Get 

It is obvious that in comparison Expression vs Reflection, Expression approach is a winner. This of course mean that, as with the constructor, you previously compile the expression and then use the compiled expression to read the property value as expression compilation as an expensive operation and should be cached.

Accessing property setter method

 We checked reading property value, but let's how to set the property value of an object instance. 

        private static void RegularSet()
        {
            var instance = new Person();
            for (int i = 0; i < 1000000; i++)
            {
                instance.Name="TEST";
            }
        }

        private static void ReflectionSet()
        {
            var instance = new Person();
            var type = instance.GetType();
            for (int i = 0; i < 1000000; i++)
            {
                type.GetProperty("Name").SetValue(instance,"TEST");
            }
        }

        private static void ExpressionSet()
        {
            var instance = new Person();
            var type = instance.GetType();

            var instanceParam = Expression.Parameter(type);
            var argumentParam = Expression.Parameter(typeof(Object));

            var propertyInfo = type.GetProperty("Name");

            var expression = Expression.Lambda<Action<Person, Object>>(
                           Expression.Call(instanceParam, propertyInfo.GetSetMethod(), Expression.Convert(argumentParam, propertyInfo.PropertyType)),
                           instanceParam, argumentParam
                         ).Compile();

            for (int i = 0; i < 1000000; i++)
            {
                expression(instance,"TEST");
            }
        }

    

If we measure the execution time of all three methods for setting the property value we will get pretty much the same values as we did for the get method.

Regular Set:            8
Reflection Set:         379
Expression Set:         10

Reflection Set

References

Disclaimer

Purpose of the code contained in snippets or available for download in this article is solely for learning and demo purposes. Author will not be held responsible for any failure or damages caused due to any other usage.


About the author

DEJAN STOJANOVIC

Dejan is a passionate Software Architect/Developer. He is highly experienced in .NET programming platform includion ASP.NET MVC and WebApi. He likes working on new technologies and exciting challenging projects

CONNECT WITH DEJAN  Loginlinkedin Logintwitter Logingoogleplus Logingoogleplus

JavaScript

read more

SQL/T-SQL

read more

Umbraco CMS

read more

PowerShell

read more

Comments for this article