2012-02-27 70 views
4

我正在查找一個示例如何使用Telerik網格框架的特定部分(ASP.NET MVC3,但這不是真的在這裏相關)。他們有一段代碼,這需要過濾器說明的列表,並建立一個表達式:Linq表達式語法和編譯

System.Linq.Expressions.Expression<Func<MyModel, bool> exp = 
       ExpressionBuilder.Expression<MyModel>(listOfFilters); 

好了,我覺得這很好。表達式包裝一個lambda,它在MyModel上運行以生成一個布爾值。大。現在,他們的例子只是下降到這一點,像這樣一個地方:

someList = someList.Where(exp); 

對此我推測應該是「哎應用該表達列表中的所有項目(這當然是通用爲MyModel太)然而, VS聲稱代碼不能編譯,我得到「沒有超載存在或者System.Func有一些無效參數」

我玩弄了它,發現我可以編譯表達式,

someList = someList.Where(x => exp.Compile()(x)); 

哪個編譯和會pro可以工作,但這讓我感到不舒服,因爲我現在明顯在我所知道的範圍之外工作。

爲什麼(IDE設置,標誌,陳舊文檔)示例的方法不起作用有一些原因嗎? 對我的黑客和示例有一個粗略的等價關係嗎? 我應該以不同的方式構建該hack以避免一些可怕的問題(比如,它不會每次編譯表達式時都檢查表達式中的項目,對嗎?我認爲它足夠聰明)

- - 編輯 是的,它是IEnumerable。我陷入了「所有Wheres都是平等的」陷阱。 謝謝大家!

回答

2

您是否嘗試過只是做

someList = someList.Where(exp.Compile()); 

如果someList是IEnumerable,你將需要使用exp.Compile()返回一個Func<MyModel,bool>

如果someList是IQueryable你可以使用exp.Compile()或者你可以使用exp哪些是Expression<Func<MyModel, bool>>

+0

有趣。這也有用,所以我可以清理一下我的代碼。我想那個問題是爲什麼我需要這樣做呢? – Mikeb 2012-02-27 21:15:12

+1

這是正確的。附註:這有可怕的表現,因爲編譯表達式非常昂貴。 – usr 2012-02-27 21:15:21

+4

@Mikeb IEnumerable .Where()需要一個Func,而不是一個表達式,對吧?你的Expression.Compile正在生成一個Func - 這可能是它的原因。但是,鑑於Telerik示例中的用法,我會看看Telerik框架是否具有擴展方法。 – 2012-02-27 21:18:58

2

someList是什麼類型?我假設List<T>。沒有擴展方法Where允許在List<T>IEnumerable<T>上的Expression<Func<T, bool>>

您可能習慣於將表達式發送給可查詢的表達式。 IQueryable<T>確實有一個Where擴展方法,允許Expression<Func<T, bool>>。要訪問它,你會做以下

var someQueryable = someList.AsQueryable().Where(exp); 

返回類型將由IQueryable<T>。要將它放回someList,您需要添加一個AsEnumerable()ToList(),具體取決於someList的類型。

這可能不是最好的方法,但它可以讓你按照預期使用exp

+0

http://msdn.microsoft.com/en-us/library/bb534803.aspx – 2012-02-27 21:21:24

+0

@ScottW不允許表達式。它允許'Func '。 – cadrell0 2012-02-27 21:23:57

+0

哦,我的錯誤,沒有注意到表情的一部分。 – 2012-02-27 21:24:43

3

有該Where()方法的兩個版本:一個運行在IEnumerable<T>並採取Func<T, bool>,其他作品上IQueryable<T>並採取Expression<Func<T, bool>>。原因是IQueryable<T>可以代表一些遠程數據,如數據庫表。當你查詢表格時,你不想傳送整個表格來找到你要查找的單個項目。

這就是爲什麼存在Expression的原因:它用於表示某些代碼,但是可以輕鬆處理,例如轉換爲SQL。或者你可以將它編譯成普通的IL代碼,並將其委託出去。

如果你想一個正常的內存列表進行操作(實現IEnumerable<T>,但不IQueryable<T>),你並不需要在所有的表情,你可以與代表工作,所有的時間和你的代碼很可能是更簡單並且更快。

但是,如果您想使用Expression s,您可以像您發現的那樣。有幾種選擇:

  1. 使用the AsQueryable() method。這樣,您將獲得與Expression一起使用的方法,如Where()

    someList.AsQueryable().Where(exp) 
    
  2. 通過調用the Compile() method編譯的表達。它會返回一個代理,您可以直接將其傳遞給Where()

    someList.Where(exp.Compile()) 
    

您試圖將實際編譯集合中的每個項目的表達,所以它可能會有糟糕的表現。