从F#函数构建Linq表达式,以传递给C#

7

我正在尝试在WinRT 8.1应用程序中的F#项目中使用Lex.Db数据库。

我正在按照这个C#教程进行操作。我已经成功地将Lex.Db引用添加到F#项目中,并且教程中的简单调用已经转换为f#并编译(例如:let db = new DbInstance("demo"))。

问题在于这段C#代码:

db.Map<Contact>().Key(i => i.Id)

-- 编辑 --

为了让其他人不必再继续阅读,F# 3.0中几乎不存在这个问题。请参见下面kvb的评论。解决方案如下:

db.Map<Contact>().Key(fun i => i.Id)

-- /编辑 ---

Key函数需要一个Expression<Func<Contact,'a>>类型的参数,但我无法在F#中构建它。

一个非常相似的问题出现在如何将LinQ表达式从F#传递到C#代码中。推荐的解决方案是使用LeafExpressionConverter.QuotationToLambdaExpression

我尝试了以下方法:

 type Contact() =
    member val Id = 0 with get, set
    member val FirstName = "" with get, set

 let db = new DbInstance("Demo")

 let idExpr = LeafExpressionConverter.QuotationToLambdaExpression
                        <@ fun (c : Contact) -> c.Id @>

 db.Map<Contact>().Key(idExpr) |> ignore    // <- Error

这会在idExpr上产生编译错误:

类型不匹配。期望一个Expression<Func<Contact,'a>>,但是给出了一个Expression<(Contact -> int)>。类型'Func<Contact,'a>'与类型'Contact -> int'不匹配。

这个问题:从F#函数创建Expression<Func<T, bool>>似乎直接解决了问题,但是该解决方案使用了Microsoft.FSharp.Linq.QuotationEvaluation,在F# 3.0 for WinRT中找不到。

如何将<@ fun (c : Contact) -> c.Id @>转换为Expression<Func<Contact,'a>>


2
如果你在F#中尝试 db.Map<Contact>.Key(fun i -> i.Id) 会发生什么? F# 3.0应该在你传递一个lambda表达式到期望一个Expression的位置时应用类型导向转换。 - kvb
这个代码运行起来不错,没有多余的仪式!它编译并运行正常。我现在有了一个绑定到 C# WinRT 视图的 F# 视图模型,并且视图模型只需几行代码就可以从数据库中读取数据(几乎是这样...还有一些很明显的代码来公开视图模型以进行数据绑定)。谢谢! - Stephen Hosking
1个回答

11

Microsoft.FSharp.Linq.QuotationEvaluation 在 PowerPack 中,但从 v3.0 开始,它提供的功能通过 LeafExpressionConverter 在核心中可用。您可以使用您链接的问题中的代码,但要更改为在转换部分使用 LeafExpressionConverter

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

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

谢谢!这是正确的并且可用。我可以在我的代码中使用它,如下所示:.Key(<@ fun (c : Contact) -> c.Id @> |> toLinq) - Stephen Hosking
请注意,我的原始帖子中@kvb的评论提供了一个适用于我的情况的更简单的解决方案。Daniel的解决方案将有助于在F# 3.0中使用这些不同的低级API构建表达式。 - Stephen Hosking

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接