Проблема с параметром MethodInfo.Invoke

Я читаю и записываю данные в файл и из него. Данные в файле могут быть float, double, int и т.д. Тип неизвестен до выполнения. Я буду ссылаться на тип данных, хранящийся в файле как Tin. Данные считываются или записываются из массивов типа Tout. Этот тип также неизвестен до времени выполнения.

Кодовая последовательность выглядит примерно так. В методе Open Tin и Tout известны, мы можем создавать методы чтения и записи для известных типов данных.

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

Циклы чтения чтения повторяются миллионы раз и полагаются на отражение, чтобы вызвать соответствующие методы, как показано ниже.

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

При анализе этого кода с использованием профилировщика производительности я нахожу, что c collosal amount, если потрачено время, просто вызывает методы чтения чтения во время выполнения.

Как ускорить это.

Ответ 1

Да, это связано с тем, что API отражения в тысячи раз медленнее, чем прямые вызовы методов. Однако есть некоторые интересные методы для работы. Посмотрите статью Джона Скита на используя делегаты для отражения кэша.

Существует статическая стоимость установки, но после того, как вы сделали это, время, требуемое для повторного вызова делегата, эквивалентно вызовам виртуальных методов.

Существует также несколько предварительно упакованных фреймворков для достижения того же.

Ответ 2

Это сделает что-нибудь для ya, почти так же быстро, как прямой вызов.

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);
    }
}

Ответ 3

Профиль, чтобы найти решение, соответствующее вашим ожиданиям:

.Net Framework предлагает множество методов для вызова динамических методов. Однако они не выполняют одинаково с точки зрения производительности, и они не менее просты в использовании.

CreateDelegate может быть тем, что вы ищете

В последних версиях .Net Framework CreateDelegate избили в 50 раз метод MethodInfo:

// 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);

Отметьте эту мою почту, чтобы увидеть контрольный показатель для различных вызовов методов.