我有以下代码是伪代码。 我想让这个函数可以接受一个 Expresstion 类型,编译这个表达式并用适当的参数调用它。
public static void f<T>(Expression<T> exp, params dynamic[] d)
{
Console.WriteLine("begin");
exp.Compile().Invoke(d[0],d[1].....);//this is pseudo-code
Console.WriteLine("end");
}
我确定 T 是一个 Action 类型。 (T 可以是 Action
、 Action<int>
等)。参数d
是一个动态类型的数组,发送给invoke。
但我不知道如何完成代码。我敢肯定,实现起来并不容易。也许在 c# 中不是这样
最佳答案
您不能使用 Invoke
除非你知道确切的签名。但是,您可以使用 DynamicInvoke
,例如:
((Delegate)exp.Compile()).DynamicInvoke(d);
请注意 dynamic
以上没有任何意义 - d
也可以是object[]
.
另一种稍微复杂一些的方法 - 将其编译为 Func<object[]>
, 并重新编写表达式 ( ExpressionVisitor
) 以将“参数 n” (来自原始 exp
) 替换为 p[n]
, 其中p
是单ParameterExpression
和 n
是 ConstantExpression
的 n
. 如果您要存储并积极地重新使用已编译的 lambda,这可能是有利的。但在您的特定场景中,您是在每次调用时进行编译,因此这没有任何好处。
这是一个例子,但这主要是为了以后有类似场景的读者,但是编译委托(delegate)被重新使用;这种重写的“优势”是它避免了 Delegate.DynamicInvoke
的性能影响。 , 同时保留 object[] => object
Delegate.DynamicInvoke
的签名;但这只有在委托(delegate)被多次使用时才有用。目前(每次调用编译)这里的大部分“工作”将在表达式编译和 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);
}
}
}
关于c# - c#中的表达式和委托(delegate),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16663567/