MethodInfo.Invoke性能问题

Bas*_*das 17 .net c# invoke

我正在读取文件和从文件写入数据.文件中的数据可以是浮点数,双精度数,整数等.直到运行时才知道该类型.我将把存储在文件中的数据类型称为Tin.数据被读入或写入Tout类型的数组.直到运行时才知道这种类型.

代码序列是这样的.在已知的Open方法Tin和Tout中,我们可以为已知数据类型创建读写方法.

Open(...)
{
   MethodInfo ReadMethod = typeof(...)GetMethod("ReadGeneric").MakeGenericMethod(new Type[] {typeof(Tin), typeof(Tout)}));
}
Run Code Online (Sandbox Code Playgroud)

读写循环重复数百万次,依赖于反射来调用适当的方法,如下所示.

Read loop
{
   var values = (Tout[])ReadMethod.Invoke(this,new object[]{index});
   process ...
}
Run Code Online (Sandbox Code Playgroud)

当使用性能分析器检查此代码时,如果只花时间调用运行时读写方法,我会发现c collosal amount.

我该如何加快速度呢?

Dr.*_*ABT 24

是的,这是因为反射API比直接方法调用慢了数千倍.然而,有一些有趣的技术可以解决这个问题.查看Jon Skeet关于使用委托缓存反射的文章.

存在静态设置成本,但是一旦完成,重复调用委托的时间等同于虚方法调用.

还有一些预先打包的框架可以实现同样的功能.


Dan*_*nry 7

这对你来说都有所作为,几乎与直接通话一样快.

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);
    }
}
Run Code Online (Sandbox Code Playgroud)