Setting data through reflection; SetValue

In C#/.NET, you can set data from an object using reflection which can be useful for things like mapping and testing. Typically, you’d use direct access, but reflection allows you to set data to fields and properties that you were un-aware of at compile time. This can save you a lot of code. But what are the performance implications?

Turns out that setting data directly from a property or field is 60-150 times faster than using the “SetValue” method.

Also note that the “Reflection Field Accessor” is way faster (6.3 times) than the “Reflection Property Accessor”! So accessing fields through reflection is much faster than accessing properties through reflection, but both are much slower than direct access.

Test type Time Iterations/s Difference
Direct Property Accessor 34 ms 147.058.823 154 times faster than reflection
Reflection Property Accessor 5250 ms 952.380  
Direct Field Accessor 19 ms 263.157.894 59 times faster than reflection
Reflection Field Accessor 1243 ms 4.022.526  

Comparing Property Setter Methods
Direct Property Accessor…
  5000000 iterations took 34 ms, 147058823,529412 iterations/s
Reflection Property Accessor…
  5000000 iterations took 5250 ms, 952380,952380952 iterations/s
Direct access is 154 times faster than reflection access

Comparing Field Setter Methods
Direct Field Accessor…
  5000000 iterations took 19 ms, 263157894,736842 iterations/s
Reflection Field Accessor…
  5000000 iterations took 1243 ms, 4022526,14641995 iterations/s
Direct access is 65 times faster than reflection access
Done, press r to go again!

Here’s the actual code for performing these tests;

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            while (true)
            {
                const int iterations = 5000000;

                Console.WriteLine("Comparing Property Setter Methods");
                long direct = TestDirectPropertyAccess(iterations);
                long reflection = TestReflectionPropertyAccess(iterations);
                Console.WriteLine(
                    "Direct access is {0} times faster than reflection access",
                    reflection / direct);

                Console.WriteLine();
                Console.WriteLine();

                Console.WriteLine("Comparing Field Setter Methods");
                direct = TestDirectFieldAccess(iterations);
                reflection = TestReflectionFieldAccess(iterations);
                Console.WriteLine(
                    "Direct access is {0} times faster than reflection access",
                    reflection / direct);

                Console.WriteLine("Done, press r to go again!");
                if (Console.ReadKey().KeyChar != 'r')
                {
                    return;
                }
            }
        }

        private static long TestDirectPropertyAccess(int iterations)
        {
            ClassWithProperty cwp = new ClassWithProperty();
            Console.WriteLine("Direct Property Accessor...");

            Stopwatch sw = Stopwatch.StartNew();
            List<string> list = new List<string>();
            for (int i = 0; i < iterations; i++)
            {
                cwp.MyProperty = list;
            }

            Console.WriteLine(
                "  {0} iterations took {1} ms, {2} iterations/s",
                iterations,
                sw.ElapsedMilliseconds,
                iterations / (sw.ElapsedMilliseconds / 1000.0));

            return sw.ElapsedMilliseconds;
        }

        private static long TestReflectionPropertyAccess(int iterations)
        {
            ClassWithProperty cwp = new ClassWithProperty();
            PropertyInfo propertyInfo =
                typeof(ClassWithProperty)
                    .GetProperties()
                    .Single(prop => prop.Name == "MyProperty");

            object[] emptyArray = new object[0];

            Console.WriteLine("Reflection Property Accessor...");
            Stopwatch sw = Stopwatch.StartNew();
            List<string> list = new List<string>();
            for (int i = 0; i < iterations; i++)
            {
                propertyInfo.SetValue(cwp, list, emptyArray);
            }

            Console.WriteLine(
                "  {0} iterations took {1} ms, {2} iterations/s",
                iterations,
                sw.ElapsedMilliseconds,
                iterations / (sw.ElapsedMilliseconds / 1000.0));

            return sw.ElapsedMilliseconds;
        }

        private static long TestDirectFieldAccess(int iterations)
        {
            ClassWithProperty cwp = new ClassWithProperty();
            Console.WriteLine("Direct Field Accessor...");

            Stopwatch sw = Stopwatch.StartNew();
            List<string> list = new List<string>();
            for (int i = 0; i < iterations; i++)
            {
                cwp.MyField = list;
            }

            Console.WriteLine(
                "  {0} iterations took {1} ms, {2} iterations/s",
                iterations,
                sw.ElapsedMilliseconds,
                iterations / (sw.ElapsedMilliseconds / 1000.0));

            return sw.ElapsedMilliseconds;
        }

        private static long TestReflectionFieldAccess(int iterations)
        {
            ClassWithProperty cwp = new ClassWithProperty();
            FieldInfo fieldInfo =
                typeof(ClassWithProperty)
                    .GetFields()
                    .Single(prop => prop.Name == "MyField");

            object[] emptyArray = new object[0];

            Console.WriteLine("Reflection Field Accessor...");

            Stopwatch sw = Stopwatch.StartNew();
            List<string> list = new List<string>();
            for (int i = 0; i < iterations; i++)
            {
                fieldInfo.SetValue(cwp, list);
            }

            Console.WriteLine(
                "  {0} iterations took {1} ms, {2} iterations/s",
                iterations,
                sw.ElapsedMilliseconds,
                iterations / (sw.ElapsedMilliseconds / 1000.0));

            return sw.ElapsedMilliseconds;
        }
    }

    public class ClassWithProperty
    {
        public ClassWithProperty()
        {
            MyProperty = new List<string>();
            MyField = new List<string>();
        }

        // I know, totally wrong naming and everything...
        public List<string> MyField;
        public List<string> MyProperty { get; set; }
    }
}

About mfagerlund
Writes code in my sleep - and sometimes it even compiles!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: