来给反射调用加加速(1):利用表达式树
众所周知,反射调用,速度很慢,那怎么办?有什么方法提速么?
有啊,这不,我就介绍一下如何利用表达式树来加速反射调用。
那为什么表达式树比反射快呢?
因为,表达式树可以用Emit生成强类型委托。
好吧,让我们看看如何操作:
1. 一定要定义强类型委托,尤其是签名
/// <summary> /// Represents a generic delegate to a function. /// </summary> public delegate object LateBoundFunc(object target, object[] arguments); /// <summary> /// Represents a generic delegate to a procedure. /// </summary> public delegate void LateBoundProc(object target, object[] arguments);
2. 定义好了,那我们看如何构造:
/// <summary> /// A factory for delegates. /// </summary> public static class DelegateFactory { /// <summary> /// Creates a delegate to the specified method. /// </summary> /// <typeparam name="T">Should be a <see cref="LateBoundFunc"/> or <see cref="LateBoundProc"/>.</typeparam> /// <param name="method">The method to create the delegate for.</param> /// <returns>The delegate.</returns> public static T Create<T>(MethodInfo method) { var instanceParameter = Expression.Parameter(typeof(object), "target"); var argumentsParameter = Expression.Parameter(typeof(object[]), "arguments"); var call = Expression.Call( Expression.Convert(instanceParameter, method.DeclaringType), method, CreateParameterExpressions(method, argumentsParameter) ); var lambda = Expression.Lambda<T>( typeof(LateBoundProc).IsAssignableFrom(typeof(T)) ? call : (Expression)Expression.Convert(call, typeof(object)), instanceParameter, argumentsParameter ); return lambda.Compile(); } private static Expression[] CreateParameterExpressions(MethodInfo method, Expression argumentsParameter) { return method.GetParameters().Select( (parameter, index) => Expression.Convert( Expression.ArrayIndex(argumentsParameter, Expression.Constant(index)), parameter.ParameterType ) ).ToArray(); } }
okay ,构造好了,如何使用呢?
public Procedure(MethodInfo info, IThreadPool threadPool) : base(info, threadPool) { _theDelegate = DelegateFactory.Create<LateBoundProc>(info); }