【发布时间】:2012-05-19 01:12:01
【问题描述】:
我正在使用带有 .NET 4.5 beta 的 F# 3.0,我正在尝试将 Expr<'a -> 'b> 类型的 F# 引用转换为 LINQ Expression<Func<'a, 'b>>。
我发现了几个可以解决此问题的问题,但这些技术似乎不再起作用,可能是由于 F# 3.0 或 .NET 4.5 的变化。
在这两种情况下,当我从任一问题的解决方案中运行代码时,以下操作都会引发异常:
mc.Arguments.[0] :?> LambdaExpression
...其中mc 是MethodCallExpression。例外是:
System.InvalidCastException:无法将“System.Linq.Expressions.MethodCallExpressionN”类型的对象转换为“System.Linq.Expressions.LambdaExpression”类型。
不,MethodCallExpressionN 末尾的额外“N”不是拼写错误。有人有建议吗?谢谢。
更新
这是一个完整的复制品。事实证明,这段代码在 <@ fun x -> x + 1 @> 这样的表达式上运行良好。我的问题是,就我而言,我需要将Expr<'a -> 'b> 转换为Expr<'a -> obj>,这样我就不必用box 乱扔我的所有lambda 表达式。我通过将原始表达式拼接到这个表达式中来做到这一点:<@ %exp >> box @>。这会生成一个类型正确的对象,但转换为 Expression<Func<'a, obj>> 的代码不再有效。
module Expr =
open System
open System.Linq.Expressions
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.QuotationEvaluation
let rec private translateExpr (linq:Expression) =
match linq with
| :? MethodCallExpression as mc ->
let le = mc.Arguments.[0] :?> LambdaExpression
let args, body = translateExpr le.Body
le.Parameters.[0] :: args, body
| _ -> [], linq
let ToFuncExpression (expr:Expr<'a -> 'b>) =
let args, body = expr.ToLinqExpression() |> translateExpr
Expression.Lambda<Func<'a, 'b>>(body, Array.ofList args)
let exp = <@ fun x -> x + 1 @>
let r = Expr.ToFuncExpression <@ %exp >> box @>
printfn "%A" r
【问题讨论】:
-
也许你因为使用无点风格而受到惩罚。如果你改用
<@ fun x -> %exp x |> box @>会发生什么?当您使用无点样式时,您要转换的表达式不是 lambda,而是一个应用程序。 -
@kvb - 这是个好主意,但是当我使用该构造时,它会在
%exp下划线并告诉我“此值不是函数,无法应用”并拒绝编译。跨度> -
但是,
<@ fun x -> x |> %exp |> box @>可以编译。不幸的是,当我尝试转换它时,它得到了同样的错误。 -
expr.ToLinqExpression()现在在F#中为Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.QuotationToExpression expr