你不能使用Invoke
,除非你知道確切的簽名。你可以,但是,使用DynamicInvoke
,例如:
((Delegate)exp.Compile()).DynamicInvoke(d);
注意的是,在上述dynamic
無濟於事 - d
也可以同樣是object[]
。
其他的,稍微複雜一些,的方法 - 將其編譯爲Func<object[]>
,並用p[n]
,其中p
是一個重新寫入表達式(ExpressionVisitor
)取代「參數n」(從原始exp
)單個和n
是ConstantExpression
的n
。這可能是有利的如果你要存儲並積極地重新使用編譯的lambda。但是在您的特定場景中,您正在編譯每次調用,因此這沒有任何好處。
下面是一個例子,但這主要是爲了後面的讀者使用類似的情況,但編譯後的代表被重用;這個重寫的「優點」是它避免了Delegate.DynamicInvoke
的性能影響,同時保留簽名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);
}
}
}