c#中的表达式和委托

时间:2013-05-21 06:33:38

标签: c# dynamic delegates lambda expression

我的代码是伪代码。 我想让这个函数可以接受一个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可以是ActionAction<int>等。)。参数d是一个动态类型的数组,它被发送到调用。

但我不知道如何完成代码。我确信这不容易实现。也许在c#

中不可能是真的

2 个答案:

答案 0 :(得分:3)

除非您知道确切的签名,否则无法使用Invoke。但是,您可以使用DynamicInvoke,例如:

((Delegate)exp.Compile()).DynamicInvoke(d);

请注意,上述dynamic没有任何意义 - d也可能是object[]

另一种稍微复杂的方法 - 将其编译为Func<object[]>,并重写表达式(ExpressionVisitor)以替换“参数n”(来自原始{{ 1}})exp,其中p[n]是单pParameterExpressionn ConstantExpression。这可能是有利的如果你要存储并积极地重新使用已编译的lambda。但是在您的特定方案中,您正在编译每次调用,因此这没有任何好处。

这是一个例子,但这主要是针对具有类似场景的后来读者,但是重新使用已编译的委托的情况;这种重写的“优势”在于,它保留了n的性能影响,同时保留了Delegate.DynamicInvoke的{​​{1}}签名;但这仅在代理被多次使用时才有用。目前(每次调用编译)这里的大部分“工作”将在表达式编译和JIT编译中。

object[] => object

答案 1 :(得分:2)

public static void F<T>(Expression<T> exp, params object[] d)
{
    Console.WriteLine("begin");

    var del = exp.Compile() as Delegate;
    del.DynamicInvoke(d);

    Console.WriteLine("end");
}

然后:

F<Action<int>>(i => Console.WriteLine(i), 5);

或:

F<Action<string, int>>((s, i) => Console.WriteLine("{0} : {1}", s, i), "Hello", 5);