MethodInfo.Invoke performance issue

淺唱寂寞╮ 提交于 2019-11-29 05:46:20
Dr. ABT

Yes, this is due to the fact that the reflection API is thousands of times slower than direct method calls. There are some interesting techniques to work around this however. Check out Jon Skeet's article on using delegates to cache reflection.

There is a static setup cost but once you have done that the time to invoke the delegate repeatedly is equivalent to virtual method calls.

There are also some pre-packaged frameworks to achieve the same thing.

This'll do anything for ya, almost as fast as a direct call.

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

public class FastMethodInfo
{
    private delegate object ReturnValueDelegate(object instance, object[] arguments);
    private delegate void VoidDelegate(object instance, object[] arguments);

    public FastMethodInfo(MethodInfo methodInfo)
    {
        var instanceExpression = Expression.Parameter(typeof(object), "instance");
        var argumentsExpression = Expression.Parameter(typeof(object[]), "arguments");
        var argumentExpressions = new List<Expression>();
        var parameterInfos = methodInfo.GetParameters();
        for (var i = 0; i < parameterInfos.Length; ++i)
        {
            var parameterInfo = parameterInfos[i];
            argumentExpressions.Add(Expression.Convert(Expression.ArrayIndex(argumentsExpression, Expression.Constant(i)), parameterInfo.ParameterType));
        }
        var callExpression = Expression.Call(!methodInfo.IsStatic ? Expression.Convert(instanceExpression, methodInfo.ReflectedType) : null, methodInfo, argumentExpressions);
        if (callExpression.Type == typeof(void))
        {
            var voidDelegate = Expression.Lambda<VoidDelegate>(callExpression, instanceExpression, argumentsExpression).Compile();
            Delegate = (instance, arguments) => { voidDelegate(instance, arguments); return null; };
        }
        else
            Delegate = Expression.Lambda<ReturnValueDelegate>(Expression.Convert(callExpression, typeof(object)), instanceExpression, argumentsExpression).Compile();
    }

    private ReturnValueDelegate Delegate { get; }

    public object Invoke(object instance, params object[] arguments)
    {
        return Delegate(instance, arguments);
    }
}
Fab

Profile to find the solution that matches your expectations :

.Net Framework offers plenty of methods to invoke dynamically methods. However they don't perform equally in terms of performance and they are not equally easy to use.

CreateDelegate may be what you're looking for

In the recent versions of .Net Framework, CreateDelegate beat by a factor 50 the MethodInfo invoke:

// The following should be done once since this does some reflection
var method = typeof (...).GetMethod("ReadGeneric");
// Here we create a Func that targets the instance of type which has the 
// ReadGeneric method
var func = (Func<Tin, Tout[]>)_method.CreateDelegate(typeof(Func<Tin, Tout[]>), target);

// Func will be 50x faster than MethodInfo.Invoke
// use func as a standard Func like 
// var tout = func(index);

Check this post of mine to see benchmark on different method invocations

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!