我正在使用F#3.0与.NET 4.5测试版,并且我试图将Expr<'a -> 'b>
类型的F#引用转换为LINQ Expression<Func<'a, 'b>>
。如何将EXPR <'a ->'b>转换为表达式<Func <'a, obj>>
我发现了几个有解决此问题的问题,但这些技术似乎不再工作,可能是由于F#3.0或.NET 4.5中的更改。
在这两种情况下,当我从任何一个问题的解决方案运行的代码,下列行为将引发异常:
mc.Arguments.[0] :?> LambdaExpression
...其中mc
是MethodCallExpression
。唯一的例外是:
System.InvalidCastException:无法转换类型 'System.Linq.Expressions.MethodCallExpressionN' 的目的为类型 'System.Linq.Expressions.LambdaExpression'。
不,在MethodCallExpressionN
末尾多余的“N”不是拼写错误。有没有人有建议?谢谢。
UPDATE
下面是一个完整再现。事实证明,这个代码在<@ 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
@kvb - 这是一个很好的想法,但是当我使用该构造时,它强调'%exp'并告诉我“这个值不是函数并且不能被应用”并拒绝编译。 –
但是,'<@ fun x -> x |>%exp |> box @>'不会编译。不幸的是,当我尝试转换它时,它会得到相同的错误。 –