정확한 서명을 알지 못하는 한 Invoke
을 사용할 수 없습니다. 당신은, 그러나, 예를 들어, DynamicInvoke
사용할 수 있습니다 위의 dynamic
은 아무 가치가 없다는 것을
((Delegate)exp.Compile()).DynamicInvoke(d);
주 - d
은 단지뿐만 아니라 object[]
을 수 있습니다.
다른, 약간 더 복잡한 접근 방식 - Func<object[]>
로 컴파일하고 p
가있다 p[n]
과 식 (ExpressionVisitor
) (원래 exp
에서) "파라미터 n"을 대체 할을 다시 작성하는 것 단일 ParameterExpression
및 n
은 ConstantExpression
이 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);
}
}
}