【问题标题】:Fastest way to compute an expression func result given parameters给定参数计算表达式 func 结果的最快方法
【发布时间】:2017-11-28 23:06:37
【问题描述】:

我收到一个Expression<Func<...,...,...,TResult>>(随机,但参数数量固定)实例,其形式为一般Expression 类型。

例如:

Expression<Func<int,int,int>> adderExpression = (a,b) => a+b;
LambdaExpression receivedExpression = adderExpression;
//Later on, I get only the receivedExpression variable and an array of values for which I have to compute:
var values = new object[] {3, 4};
var result = receivedExpression.Compile().DynamicInvoke(values);

我唯一可以访问的是receivedExpression 变量和一个对象值数组,我必须为其计算应用编译表达式的结果。

receivedExpression 不会改变:一旦我得到它,它就会保持不变。

根据我的情况,计算result 变量的最快方法是什么? DynamicInvoke 在这种情况下非常慢,我想知道是否有更快的方法来计算结果。

【问题讨论】:

  • 您的代码无法编译,因为Expression 上没有方法Compile
  • 应该是LambdaExpression receivedExpression
  • 你知道所涉及的任何类型,尤其是返回类型吗?

标签: c# dynamic reflection lambda expression


【解决方案1】:

您可以创建一个已编译委托,该委托接受参数数组并使用Invoke 调用传入的Expression,从而有效地动态创建等效于:

var rec = receivedExpression.Compile();
var f = (object[] p) => (object)rec.Invoke((type0)p[0],(type1)p[1],...);

首先,您需要将receivedExpression 的(未知)返回类型转换为object,以便创建强类型委托:

var fr = Expression.Lambda(Expression.Convert(receivedExpression.Body, typeof(object)), receivedExpression.Parameters);

然后,您可以为接受 object[] 并调用具有固定数量和类型参数的 lambda 的 lambda 创建 Expression

首先你需要一个 lambda 参数:

var arg = Expression.Parameter(typeof(object[]));

然后您需要将该object[] 参数的每个成员转换为正确的类型以传递给receivedExpression

var args = values.Select((v, i) => Expression.Convert(Expression.ArrayIndex(arg, Expression.Constant(i)), v.GetType())).ToArray();

然后你可以创建新的 lambda:

var frs = Expression.Lambda(Expression.Invoke(fr, args), arg);

然后编译包含传入的 Expression 的 lambda:

var frsc = (Func<object[], object>)frs.Compile();

最后,您可以使用新的 lambda 有效地调用 receivedExpression

object result = frsc.Invoke(values);

【讨论】:

  • 不错的一个!我想知道是否有比 Invoke 更快的方法来执行此操作。不过,您的方法从 ~709ns(使用 DynamicInvoke)到 56ns(使用您的方法)。
  • Invoke 是编译器将常规函数调用转换为Expression 树的方式,所以我认为它尽可能高效。检查对 Func&lt;&gt; 的文字调用显示它在 IL 中使用 Invoke
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-22
  • 1970-01-01
  • 2018-03-25
  • 1970-01-01
  • 2017-05-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多