我正在从文件读取和写入数据。文件中的数据可以是浮点数,双精度数,整数等。直到运行时才知道该类型。我将把存储在文件中的数据类型称为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。
如何加快速度。
答案 0 :(得分:20)
是的,这是因为反射API比直接方法调用慢了数千倍。然而,有一些有趣的技术可以解决这个问题。查看Jon Skeet关于using delegates to cache reflection的文章。
存在静态设置成本,但是一旦完成,重复调用委托的时间等同于虚方法调用。
还有一些pre-packaged frameworks可以实现同样的目标。
答案 1 :(得分:6)
这会为你做任何事情,几乎和直接电话一样快。
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);
}
}
答案 2 :(得分:0)
.Net Framework提供了大量调用动态方法的方法。但是,它们在性能方面表现不佳,而且使用起来并不容易。
在.Net Framework的最新版本中,CreateDelegate在MethodInfo调用时击败因子50:
// 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);
检查此post of mine以查看不同方法调用的基准