我正在使用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 @>'不會編譯。不幸的是,當我嘗試轉換它時,它會得到相同的錯誤。 –