Invoke
除非您知道确切的签名,否则您不能使用。但是,您可以使用DynamicInvoke
,例如:
((Delegate)exp.Compile()).DynamicInvoke(d);
请注意,dynamic
上面的 没有任何用途 -d
也可以object[]
。
另一种稍微复杂的方法 - 将其编译为 a Func<object[]>
,并重新编写表达式 ( ExpressionVisitor
) 以将“参数 n”(来自原始exp
)替换为,p[n]
其中p
是单个ParameterExpression
并且n
是 a ConstantExpression
。如果您要存储并积极重用已编译的 lambda,n
这可能是有利的。但是在您的特定情况下,您是按调用编译的,所以这没有任何好处。
这是一个例子,但这主要是为以后有类似场景的读者准备的,但是编译的委托被重用;这种重写的“优点”是它避免了对性能的影响Delegate.DynamicInvoke
,同时保留了; 的object[] => object
签名Delegate.DynamicInvoke
。但这只有在多次使用委托时才有用。目前(每次调用编译)这里的大部分“工作”都将在表达式编译和 JIT 编译中进行。
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
static class Program {
static void Main() {
Expression<Func<int, float, double>> exp = (i, f) => i * f;
var func = CompileToBasicType(exp);
object[] args = { 3, 2.3F };
object result = func(args); // 6.9 (double)
}
static Func<object[], object> CompileToBasicType(LambdaExpression exp) {
ParameterExpression arg =
Expression.Parameter(typeof(object[]), "args");
Dictionary<Expression, Expression> lookup =
new Dictionary<Expression, Expression>();
int i = 0;
foreach (var p in exp.Parameters) {
lookup.Add(p, Expression.Convert(Expression.ArrayIndex(
arg, Expression.Constant(i++)), p.Type));
}
var body = Expression.Convert(
new ReplaceVisitor(lookup).Visit(exp.Body), typeof(object));
return Expression.Lambda<Func<object[], object>>(body, arg).Compile();
}
class ReplaceVisitor : ExpressionVisitor {
private readonly Dictionary<Expression, Expression> lookup;
public ReplaceVisitor(Dictionary<Expression, Expression> lookup) {
if (lookup == null) throw new ArgumentNullException("lookup");
this.lookup= lookup;
}
public override Expression Visit(Expression node) {
Expression found;
return lookup.TryGetValue(node, out found) ? found
: base.Visit(node);
}
}
}