DynamicMethod vs Reflection

Introduction

DynamicMethod was introduced in .Net 2.0, and in this article I am going to explain how to use DynamicMethod class as an alternative to Reflection to achieve a better performance.

DynamicMethod is the most efficient way to generate and execute a small amount of code. For instance, you can leverage DynamicMethod class to replace System.Reflection by generating and executing methods at run time, without having to generate dynamic assemblies and dynamic types to contain the methods. The executable code created by the JIT compiler will be reclaimed when the DynamicMethod object is reclaimed. This approach is much faster and provides exceptional performance comparing to using Reflection.

The Problem

System.Reflection is too slow and will cost you performance degradation if you decide to use it heavily in your application. However, in some domains like building compilers or ORM databases, using reflection is inevitable.

The Solution

Luckily, DynamicMethod could substitute Reflection, while offering a significant performance increase. To prove that, I have created an application which instantiates new objects in a tight loop using Reflection, DynamicMethod and regular object instantiation using new keyword.

InstantiateObject

The above screenshot shows the results of running the code in a tight loop 1,000,000,00 times. As shown, the DynamicMethod is roughly 6 times faster than Reflection (You may get different results when you try it on your machine), while is almost close to using the new keyword.

public delegate object InstanceCreator();
public InstanceCreator CreateInstance() where T : class
{
    InstanceCreator result = null;
    var constructor = typeof(T).GetConstructor(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[0], null);
    if (constructor != null)
    {
        var dynamicMethod = new DynamicMethod("InstantiateObject", MethodAttributes.Static | MethodAttributes.Public, CallingConventions.Standard, typeof(object), null, typeof(T), true);
        var codeGenerator = dynamicMethod?.GetILGenerator();
        if (codeGenerator != null)
        {
            codeGenerator.Emit(OpCodes.Newobj, constructor);
            codeGenerator.Emit(OpCodes.Ret);
            result = dynamicMethod.CreateDelegate(typeof(InstanceCreator)) as InstanceCreator;
        }
    }

    return result;
}

The InstanceCreator delegate is as a return type of the CreateInstance method which creates and compile code dynamically. The delegate then points to this generated code which can be invoked later to perform the specified task.

The same idea could be applied to create setters and getters delegates to set/get private fields using DynamicMethod class as shown blow

public delegate object Getter(object source);
public Getter CreateGetter(FieldInfo fieldInfo) where T : class
{
    Getter result = null;
    var dynamicGet = new DynamicMethod("DynamicGet", typeof(object), new Type[] { typeof(object) }, typeof(T), true);
    var getGenerator = dynamicGet?.GetILGenerator();
    if (getGenerator != null)
    {
        getGenerator.Emit(OpCodes.Ldarg_0);
        getGenerator.Emit(OpCodes.Ldfld, fieldInfo);
        BoxIfNeeded(fieldInfo.FieldType, getGenerator);
        getGenerator.Emit(OpCodes.Ret);
        result = dynamicGet.CreateDelegate(typeof(Getter)) as Getter;
    }

    return result;
}

public delegate void Setter(object source, object value);
public Setter CreateSetter(FieldInfo fieldInfo) where T : class
{
    Setter result = null;

    var dynamicSet = new DynamicMethod("DynamicSet", typeof(void), new Type[] { typeof(object), typeof(object) }, typeof(T), true);
    var setGenerator = dynamicSet?.GetILGenerator();

    if (setGenerator != null)
    {
        setGenerator.Emit(OpCodes.Ldarg_0);
        setGenerator.Emit(OpCodes.Ldarg_1);
        UnboxIfNeeded(fieldInfo.FieldType, setGenerator);
        setGenerator.Emit(OpCodes.Stfld, fieldInfo);
        setGenerator.Emit(OpCodes.Ret);

        result = dynamicSet.CreateDelegate(typeof(Setter)) as Setter;
    }
    return result;
}

private void BoxIfNeeded(Type type, ILGenerator generator)
{
    if (type.IsValueType)
        generator.Emit(OpCodes.Box, type);
}

private void UnboxIfNeeded(Type type, ILGenerator generator)
{
    if (type.IsValueType)
        generator.Emit(OpCodes.Unbox_Any, type);
}

You could encapsulate all these methods into a DynamicMethodFactory class and use them as the following

DynamicMethodFactory dynamicMethodFactory = new DynamicMethodFactory();
InstanceCreator instanceCreator = dynamicMethodFactory.CreateInstance();
object result = instanceCreator();
DynamicMethodFactory dynamicMethodFactory = new DynamicMethodFactory();
FieldInfo fieldInfo = typeof(TestClass).GetField("property", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
Setter setter = dynamicMethodFactory.CreateSetter(fieldInfo);
setter(testClass, "test");
DynamicMethodFactory dynamicMethodFactory = new DynamicMethodFactory();
FieldInfo fieldInfo = typeof(TestClass).GetField("property", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
Getter getter = dynamicMethodFactory.CreateGetter(fieldInfo);
string value = (string)getter(testClass);

 

Conclusion

DynamicMethod class offers a significant improve to system performance by creating and compiling code at run time. This approach is much faster than using System.Reflection as proven by the results above.

Thank you for reading my article. I wish it helps.

Leave a comment