如何在C# / .NET中使用LINQ表达式树调用lambda函数

26 浏览
0 Comments

如何在C# / .NET中使用LINQ表达式树调用lambda函数

我想使用表达式树来动态创建一个调用lambda的方法。以下代码对于第一次调用ComposeLambda函数运行良好,但第二次调用失败,并显示以下错误消息。

“为调用方法'Int32 lambda_method(System.Runtime.CompilerServices.Closure, Int32)'提供的参数数量不正确。”

{
    Func innerLambda = i => i + 1;    
    var composedLambda = ComposeLambda(innerLambda);
    Console.WriteLine(composedLambda.DynamicInvoke(0));
    var composedLambda2 = ComposeLambda(composedLambda);
    Console.WriteLine(composedLambda2.DynamicInvoke(0));
}
private static Delegate ComposeLambda(Delegate innerLambda)
{
    Func outerLambda = i => i + 2;
    var parameter = Expression.Parameter(typeof (int));
    var callInner = Expression.Call(innerLambda.GetMethodInfo(), parameter);
    var callOuter = Expression.Call(outerLambda.GetMethodInfo(), callInner);
    var composedLambdaType = typeof (Func<,>).MakeGenericType(typeof (int), typeof (int));
    var composedLambdaExpression = Expression.Lambda(composedLambdaType, callOuter, parameter);
    var composedLambda = composedLambdaExpression.Compile();
    return composedLambda;
}

如何获取并传递这个闭包对象?

0
0 Comments

在C# / .NET中使用LINQ表达式树调用lambda函数的问题是什么以及如何解决的?

问题是在调用lambda函数时,使用Expression.Call(innerLambda.GetMethodInfo(), ...)是很麻烦的。相反,应该调用委托本身 - 你没有理由去操作委托的"方法" - 不仅会丢失目标(在实例方法中非常重要),还会违反隐私(例如,匿名方法是内部或私有的)。

解决方法是使用Expression.Invoke(应该与委托一起使用),这样可以正常工作。

此外,如果在编译时知道正确的委托类型,不要使用Delegate。在这种情况下,使用Func<int, int>很简单,然后可以像这样调用:composedLambda2(0)

关于这个问题的解释和教程,可以参考MSDN的基本介绍:msdn.microsoft.com/en-us/library/bb397951.aspx。还可以查看blogs.msdn.com/b/charlie/archive/2008/01/31/…,其中包含一些解释和示例。

在这个例子中,表达式树的作用是什么?你可以直接构造委托,不需要使用表达式树吗?

是的,你可以使用outerLambda = i => innerLambda(i) + 2直接实现相同的效果。实际上,如果你这样做(作为Expression<...>),我相信它将生成相同的表达式树 - 或者非常相似的树。

Expression.Constant(innerLambda)部分是如何工作的?ConstantExpression如何与委托一起使用?

Expression.Constant对于任何行为像常量值的东西都有效 - 也就是说,不依赖于表达式的其他部分,并且理想情况下是不可变的。它也适用于可变值,但请确保知道自己在做什么 - 大多数这些功能都是以函数式思维方式设计的,默认情况下是不可变的。当然,所有这些只有在编译表达式时才成立 - 如果将表达式用于其他用途(例如Entity Framework),则需要查找特定消费者的限制等信息。

一个常量值是什么?是对委托的引用还是委托的内部(返回值、副作用等)?

这没有硬性规定;尽管表达式被命名为Constant,但它实际上意味着"这是按引用传递的"。引用被嵌入到表达式中(如果编译表达式树,则还包含在委托中)。当然,值类型会被复制(除非重用装箱的值)。现在,我倾向于对函数范围外的任何可变值持有怀疑态度。

0