表达式<func <t,bool =“”>&gt;来自F#func </func <t,>

时间:2012-02-03 19:36:32

标签: linq f#

在linq中,。需要表达式&gt;谓词,我可以用F#写作

<@ fun item:'a -> condition @>    // Expr<'a -> bool>

我正在使用FSharp.Powerpack从引号构建表达式,但它给我的是一个MethodCallExpression。看起来很深,powerpack代码正确构建了lambda,但是将它包装在Convert调用中(为什么会这样?)。我想知道是否将参数转换为方法调用(一个lambda)最终会给我表达式&gt;我需要。

所以问题是转换调用的原因,以及如何使用Func签名实际获取lambda。

2 个答案:

答案 0 :(得分:12)

我不记得在我发现这段代码的地方,但这是我用来将Expr<'a -> 'b>转换为Expression<Func<'a, 'b>>的方法。希望这能解决您的问题。

open System
open System.Linq.Expressions
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.QuotationEvaluation

let toLinq (expr : Expr<'a -> 'b>) =
  let linq = expr.ToLinqExpression()
  let call = linq :?> MethodCallExpression
  let lambda = call.Arguments.[0] :?> LambdaExpression
  Expression.Lambda<Func<'a, 'b>>(lambda.Body, lambda.Parameters) 

答案 1 :(得分:7)

现在,您可以采用的一种方法是利用F#在调用期望Expression<Func<...>>的.NET类型上的方法时自动执行此转换的事实。

我不完全确定何时添加到语言中,但当然使用F#4时,您不需要将F#表达式显式转换为LINQ表达式。如果您想要首先执行此操作的原因是能够使用IQueryable LINQ API(或其他基于表达式的.NET API),那么现在它可以毫不费力地工作,例如:

someEfDataContext.MyEntities.Single(fun e -> e.Id = 42)

正常工作。虽然这看起来像普通的lambda(我们没有使用F#的表达式语法),但这会编译生成F#表达式对象的代码,然后将其传递给LeafExpressionConverter‌​.QuotationToExpressi‌on以将其转换为LINQ表达式对象。 / p>

但有时你会想直接在F#中掌握LINQ风格的表达式对象。 (例如,有时编写一个F#函数会产生一个你将在多个查询中使用的表达式。)在这种情况下,你可以编写一个这样的帮助器:

type FunAs() =
    static member LinqExpression<'T, 'TResult>(e: Expression<Func<'T, 'TResult>>) = e

看起来它什么都不做 - 它只是返回它的参数。但是,因为FunAs是.NET类型,所以F#会自动将使用fun表达式调用此调用的任何调用站点编译为生成合适的LINQ查询表达式的代码。 E.g:

let linqExpr = FunAs.LinqExpression(fun (e:MyEntity) -> e.Id = 42)

此处,linqExpr的类型为Expression<Func<MyEntity, bool>>

关键是此方法是.NET Type的成员。如果您使用普通的F#函数尝试完全相同的事情:

let funAsLinqExpression<'T, 'TResult>(e: Expression<Func<'T, 'TResult>>) = e

似乎它应该与FunAs.LinqExpression完全相同,你会发现你不能以同样的方式调用它。例如,如果您尝试这样做:

let linqExpr = funAsLinqExpression(fun (e:MyEntity) -> e.Id = 42)

你会得到一个(稍微无用的)错误:'这个函数需要太多的参数,或者在不期望函数的上下文中使用。

通过使这个函数成为.NET类型的成员,我们可以利用F#的帮助“你似乎正在调用一个期望LINQ风格表达式的.NET API,让我为你处理这个问题”功能

(可能有一些更明确的方式要求LINQ编译器为你执行同样的技巧而不将.NET类型带入图片中,但我没有找到它。)