You can't use Invoke
unless you know the exact signature. You can, however, use DynamicInvoke
, for example:
((Delegate)exp.Compile()).DynamicInvoke(d);
Note that the dynamic
in the above serves no purpose - d
could just as well be object[]
.
The other, slightly more complicated, approach - would be to compile it as a Func<object[]>
, and re-write the expression (ExpressionVisitor
) to replace "parameter n" (from the original exp
) with p[n]
, where p
is a single ParameterExpression
and n
is a ConstantExpression
of n
. This might be advantageous if you were going to store and aggressively re-use the compiled lambda. But in your specific scenario you are compiling per call, so this would have no benefit.
Here's an example, but this is mainly intended for later readers with similar scenarios, but where the compiled delegate is re-used; the "advantage" of this re-writing is that it avoids the performance impact of Delegate.DynamicInvoke
, while retaining the object[] => object
signature of Delegate.DynamicInvoke
; but this will only be useful if the delegate is being used multiple times. At the moment (compiled per call) most of the "work" here is going to be in the expression-compile and JIT-compile.
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);
}
}
}