2012-02-03 115 views
8

在LINQ,。凡需要表达>谓词,我可以在F#写成表达<Func键<T, bool>>从F#FUNC

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

我使用FSharp.Powerpack建立从表达引用,但它给我的是一个MethodCallExpression。深层次看,powerpack代码正确地构建了lambda表达式,但将其封装在Convert调用中(为什么?)。我想知道是否将方法调用(lambda)的参数转换为我需要的Expression>。

所以问题是为什么转换调用,以及如何实际得到带有Func签名的lambda。

+0

哎,没你找到一个更简单的方法来做到这一点? – nicolas 2012-05-01 13:06:16

+0

在旁注中,这里有一个相关的问题,(虽然没有引用,虽然)http://stackoverflow.com/questions/3392000/interop-between-f-and-c-sharp-lambdas – nicolas 2012-05-01 13:08:17

回答

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) 
+4

'expr.ToLinqExpression() '现在在'F#'中作为'Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.QuotationToExpression expr' – Maslow 2015-03-22 15:08:46

4

一种方法是采取的事实,即调用上期待Expression<Func<...>> .NET类型方法时,F#会自动执行这种转换。

我不完全确定何时将其添加到语言中,但肯定使用F#4,您不需要将F#表达式显式转换为LINQ。如果你想这样做摆在首位的原因是能够使用LINQ IQueryable的API(或其他基于表达式的.NET的API),那么它现在只是没有努力的工作,如:

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

刚作品。尽管这看起来像一个普通的lambda(我们还没有使用F#的表达式语法),但是它编译为生成F#表达式对象的代码,然后将其传递给LeafExpressionConverter‌​.QuotationToExpressi‌on以将它转换为LINQ表达式对象。

但有时您会想直接在F#中获得LINQ样式表达式对象。 (例如,有时它是有用的编写产生,你会在多个查询使用表达式的F#功能。)在这种情况下,你可以写这样的帮手:

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

这看起来像它什么也不做 - 它只是返回它的参数。但是,因为FunAs是一个.NET类型,所以F#会自动编译任何呼叫站点,该站点将fun表达式调用到生成合适的LINQ查询表达式的代码中。例如: -

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

这里,linqExprExpression<Func<MyEntity, bool>>类型。

关键是这个方法是一个.NET类型的成员。如果您尝试同样的事情用一个普通的F#功能:

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

这似乎像它应该是说完全一样的东西FunAs.LinqExpression,你会发现,你不能把它以同样的方式。例如,如果你试试这个:

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

你会得到一个(略无益的)错误:“这个函数的参数太多,或者在上下文中,其中一个功能不expected`使用。

通过使这个函数成为.NET类型的成员,我们可以利用F#的有用的“你似乎在调用一个需要LINQ风格表达式的.NET API,让我为你处理这个问题”特征。

(这有可能是有要求的LINQ编译器不把.NET类型到图片为您执行这个同样的伎俩,一些更明确的方式,但我还没有发现它。)

相关问题