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

Ste*_*ing 4 f# c#-to-f# windows-runtime f#-3.0

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

我正在关注C#的本教程.我成功地将一个对Lex.Db的引用添加到了一个F#项目中,并且教程中的简单调用转换为f#并编译(例如let db = new DbInstance("demo")).

问题是这个C#代码:

db.Map<Contact>().Key(i => i.Id)
Run Code Online (Sandbox Code Playgroud)

- 编辑 -

为了避免其他人进一步阅读,在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
Run Code Online (Sandbox Code Playgroud)

这会产生编译器错误idExpr:

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

这个问题:来自F#func的Expression <Func <T,bool >>似乎直接解决了这个问题,但该解决方案使用的是Microsoft.FSharp.Linq.QuotationEvaluation,我在F#3.0中找不到WinRT.

我怎么<@ fun (c : Contact) -> c.Id @>变成一个Expression<Func<Contact,'a>>

Dan*_*iel 7

Microsoft.FSharp.Linq.QuotationEvaluation在PowerPack中,但从v3.0开始,它提供的功能在Core via中可用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) 
Run Code Online (Sandbox Code Playgroud)