2012-01-04 79 views
15

我在理解表達式和函數的工作方式之間的差異時遇到了一些困難。 這個問題打開了,當有人從改變方法簽名:關於傳遞表達式與函數參數的困惑

public static List<Thing> ThingList(Func<Thing, bool> aWhere) 

public static List<Thing> ThingList(Expression<Func<Thing, bool>> aWhere) 

這打破了我的調用代碼。舊的調用代碼(合作)是這樣的:

 ... 
     object y = new object(); 
     Func<Thing, bool> whereFunc = (p) => p == y; 
     things = ThingManager.ThingList(whereFunc); 

新的代碼(不工作)看起來是這樣的:

 ... 
     object x = new object(); 
     Expression<Func<Thing, bool>> whereExpr = (p) => p == x; 
     things = ThingManager.ThingList(whereExpr); 

這裏面失敗ThingList(...)上

 var query = (from t in context.Things.Where(aWhere) 
     ... 

隨着運行時錯誤::利用表達式線

Unable to create a constant value of type 'System.Object'. Only primitive types ('such as Int32, String, and Guid') are supported in this context. 

這個例子很有意思,但我的猜測是它與本地對象變量x沒有正確「複製」到表達式中有關。

有人可以解釋一般如何處理這種情況,爲什麼Func工作,但Expression沒有?

回答

11

的原因變化幾乎可以肯定是「推」的謂詞的評價到底層存儲,它備份你的context。除了將所有Things帶入內存,然後使用Func<Thing,bool>來決定保留哪些內容,更改的API的作者決定使用IQueryable,並且需要Expression<Func<Thing,bool>>

你在錯誤的起源上是正確的:與內存中的謂詞不同,IQueryable不能使用它不知道的對象,例如: object的任意實例。

您需要做的是更改表達式以避免引用目標數據存儲不支持的數據類型對象(我假設該表達式最終進入實體框架或Linq2Sql上下文)。例如,而不是說

object x = new object(); 
Expression<Func<Thing, bool>> whereExpr = (p) => p == x; 
things = ThingManager.ThingList(whereExpr); 

你應該說

Thing x = new Thing {id = 123}; 
Expression<Func<Thing, bool>> whereExpr = (p) => p.id == x.id; 
things = ThingManager.ThingList(whereExpr); 

(你的後備存儲幾乎可以肯定明白整數)

+0

是,它使得它的方式到實體框架。我想我必須做兩個方法,一個用於Expression,另一個用於Func在必要時使用。 – Erix 2012-01-04 14:32:08

6

表達和Func鍵之間的差別在這裏的答案是更好的描述:Difference between Expression<Func<>> and Func<>

一個快速的解決方法,使再次這項工作將是編譯表達式返回到函數求。

var query = (from t in context.Things.Where(aWhere.Compile())