2012-02-03 163 views
8

在LINQ,。凡需要表達>謂詞,我可以在F#寫成表達<Func鍵<T, bool>>從F#FUNC

<@ fun item:'a -> condition @> // Expr<'a -> bool> 

我使用FSharp.Powerpack建立從表達引用,但它給我的是一個MethodCallExpression。深層次看,powerpack代碼正確地構建了lambda表達式,但將其封裝在Convert調用中(爲什麼?)。我想知道是否將方法調用(lambda)的參數轉換爲我需要的Expression>。

所以問題是爲什麼轉換調用,以及如何實際得到帶有Func簽名的lambda。

+0

哎,沒你找到一個更簡單的方法來做到這一點? – nicolas 2012-05-01 13:06:16

+0

在旁註中,這裏有一個相關的問題,(雖然沒有引用,雖然)http://stackoverflow.com/questions/3392000/interop-between-f-and-c-sharp-lambdas – nicolas 2012-05-01 13:08:17

回答

12

我記不起頭頂上哪裏找到了這段代碼,但這是我用來將Expr<'a -> 'b>轉換爲Expression<Func<'a, 'b>>。希望這會解決你的問題。現在你可以做到這一點

open System 
open System.Linq.Expressions 
open Microsoft.FSharp.Quotations 
open Microsoft.FSharp.Linq.QuotationEvaluation 

let toLinq (expr : Expr<'a -> 'b>) = 
    let linq = expr.ToLinqExpression() 
    let call = linq :?> MethodCallExpression 
    let lambda = call.Arguments.[0] :?> LambdaExpression 
    Expression.Lambda<Func<'a, 'b>>(lambda.Body, lambda.Parameters) 
+4

'expr.ToLinqExpression() '現在在'F#'中作爲'Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.QuotationToExpression expr' – Maslow 2015-03-22 15:08:46

4

一種方法是採取的事實,即調用上期待Expression<Func<...>> .NET類型方法時,F#會自動執行這種轉換。

我不完全確定何時將其添加到語言中,但肯定使用F#4,您不需要將F#表達式顯式轉換爲LINQ。如果你想這樣做擺在首位的原因是能夠使用LINQ IQueryable的API(或其他基於表達式的.NET的API),那麼它現在只是沒有努力的工作,如:

someEfDataContext.MyEntities.Single(fun e -> e.Id = 42) 

剛作品。儘管這看起來像一個普通的lambda(我們還沒有使用F#的表達式語法),但是它編譯爲生成F#表達式對象的代碼,然後將其傳遞給LeafExpressionConverter‌​.QuotationToExpressi‌on以將它轉換爲LINQ表達式對象。

但有時您會想直接在F#中獲得LINQ樣式表達式對象。 (例如,有時它是有用的編寫產生,你會在多個查詢使用表達式的F#功能。)在這種情況下,你可以寫這樣的幫手:

type FunAs() = 
    static member LinqExpression<'T, 'TResult>(e: Expression<Func<'T, 'TResult>>) = e 

這看起來像它什麼也不做 - 它只是返回它的參數。但是,因爲FunAs是一個.NET類型,所以F#會自動編譯任何呼叫站點,該站點將fun表達式調用到生成合適的LINQ查詢表達式的代碼中。例如: -

let linqExpr = FunAs.LinqExpression(fun (e:MyEntity) -> e.Id = 42) 

這裏,linqExprExpression<Func<MyEntity, bool>>類型。

關鍵是這個方法是一個.NET類型的成員。如果您嘗試同樣的事情用一個普通的F#功能:

let funAsLinqExpression<'T, 'TResult>(e: Expression<Func<'T, 'TResult>>) = e 

這似乎像它應該是說完全一樣的東西FunAs.LinqExpression,你會發現,你不能把它以同樣的方式。例如,如果你試試這個:

let linqExpr = funAsLinqExpression(fun (e:MyEntity) -> e.Id = 42) 

你會得到一個(略無益的)錯誤:「這個函數的參數太多,或者在上下文中,其中一個功能不expected`使用。

通過使這個函數成爲.NET類型的成員,我們可以利用F#的有用的「你似乎在調用一個需要LINQ風格表達式的.NET API,讓我爲你處理這個問題」特徵。

(這有可能是有要求的LINQ編譯器不把.NET類型到圖片爲您執行這個同樣的伎倆,一些更明確的方式,但我還沒有發現它。)

相關問題