【问题标题】:Build a Linq expression from an F# function, to pass to C#从 F# 函数构建 Linq 表达式,以传递给 C#
【发布时间】:2014-05-02 17:57:06
【问题描述】:

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

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

问题在于这段 C# 代码:

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

-- 编辑--

为了避免其他人进一步阅读,在 F# 3.0 中这几乎不是问题。请参阅下面的 kvb 评论。解决办法是:

db.Map&lt;Contact&gt;().Key(fun i =&gt; i.Id)

-- /编辑 ---

Key 函数需要 Expression&lt;Func&lt;Contact,'a&gt;&gt;,我无法在 F# 中构建它。

How to pass LinQ Expressions from F# to C# code 中出现了一个非常相似的问题。推荐的解决方案是使用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&lt;Func&lt;Contact,'a&gt;&gt;,但给出Expression&lt;(Contact -&gt; int)&gt;'Func&lt;Contact,'a&gt;' 类型与 'Contact -&gt; int' 类型不匹配。

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

如何将&lt;@ fun (c : Contact) -&gt; c.Id @&gt; 变成Expression&lt;Func&lt;Contact,'a&gt;&gt;

【问题讨论】:

  • 如果你在 F# 中尝试 db.Map&lt;Contact&gt;.Key(fun i -&gt; i.Id) 会发生什么? F# 3.0 应在您传递预期为 Expression 的 lambda 时应用类型导向的转换。
  • 有效#kvb,无需任何仪式!它编译并运行。我现在有一个绑定到 C# WinRT 视图的 F# 视图模型,视图模型只用这几行代码从数据库中读取(几乎......从教程和将视图模型暴露给数据绑定)。谢谢!

标签: f# windows-runtime f#-3.0 c#-to-f#


【解决方案1】:

Microsoft.FSharp.Linq.QuotationEvaluation 在 PowerPack 中,但从 v3.0 开始,它提供的功能可通过 LeafExpressionConverter 在 Core 中使用。您可以使用您链接的问题中的代码,但将其更改为使用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(&lt;@ fun (c : Contact) -&gt; c.Id @&gt; |&gt; toLinq).
  • 读者,请注意@kvb 在我的 OP 中的评论提供了一个更简单的解决方案,适用于我的情况。 Daniel 的解决方案将有助于在 F# 3.0 中使用这些各种较低级别的 API 构建表达式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-22
  • 1970-01-01
  • 2010-11-14
  • 2012-04-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多