2010-07-16 62 views
3

我們知道你不能添加一個額外的條款一樣.Where().First()爲編譯查詢,因爲這改變了查詢,並強制進行重新編譯。我想知道哪些方法可以用來「關閉」已編譯的查詢。哪些方法來關閉編譯的查詢

我知道大多數人使用.AsEnumerable().ToList(),但哪些其他方法也適用?我可以使用.AsQueryable(),還是這是一個沒有操作?

哪個更好的性能?我知道.AsEnumerable().ToList()快,但如果我想的IQueryable,是.AsEnumerable().AsQueryable().ToList()更好?

+3

「.AsEnumerable()比.ToList()更快...並且蘋果不是梨。 – spender 2010-07-16 08:51:58

+0

是的,我知道你通常會選擇你所需要的。不過,我認爲了解性能差異很重要。 – Carvellis 2010-07-16 09:03:21

回答

7

在大多數情況下,AsEnumerable().AsQueryable()可能是你想要什麼,因爲:

  • 這樣做的明確AsEnumerable(),你沒有運行的底層實現使AsQueryable()成無操作的風險,從而破壞您嘗試關閉查詢。我並不是說現在的EF使得AsQueryable()是一個無操作(據我所知,事實並非如此),只是沒有記錄行爲 - 無論是無操作還是透明地調用AsEnumerable() - 都沒有記錄所以依靠它是不安全的。
  • AsEnumerable(),不像ToList(),不加載你的整個結果在存儲器中,以便查詢。對於大型結果集來說,這很重要。理論上可能的是,對於較小的結果集,使用ToList()可能會有一些優勢(例如,優化的ToList()實現從底層提供者抽取大塊數據,而枚舉涉及更多上下文切換),但這似乎不太可能,依賴於提供者和版本,而AsEnumerable()的大結果集優勢將永遠存在。

的一個情況下我不喜歡打電話ToList()是,當我明確地確實要強制查詢現在執行。例如,如果我想在一個方法的早些​​時候捕獲查詢中的錯誤,以便稍後可以簡化錯誤處理,或者我想在繼續查詢的其餘部分之前驗證所有基礎數​​據。或者如果查詢更容易在兩個切碎時進行測試。我永遠不會這樣做,除非我知道我的記錄集將會很小,因爲在數百萬行查詢中調用ToList()會殺死你的RAM。

要回答在MSDN細節LINQ方法力查詢執行的LINQ文檔中您的其他問題,Converting Data Types。根據該頁面,ToArray()ToDictionary(),ToList()ToLookup()都強制執行查詢。

AsEnumerable(),相比之下,不強制立即執行查詢,但「關閉」查詢(這裏使用的術語,不知道是否有一個爲官一任此)。每http://msdn.microsoft.com/en-us/library/bb335435.aspx

的AsEnumerable方法可以 被用來隱藏自定義方法和 反而讓標準查詢 運營商提供。

換句話說,運行AsEnumerable將迫使像Take()Where()所有呼叫使用通用LINQ的實現,而不是anythign定製,這將導致重新編譯。

+0

謝謝,這完美地回答了我的問題。 – Carvellis 2010-07-26 08:27:31

1

哪些方法可用於「關閉」已編譯的查詢。

返回序列的方法使用延遲執行,除非該方法類似於ToXYZWhereSelectTake,Skip,GroupByOrderBy等等。返回查詢的單個對象執行力,像FirstSingleToListToArrayToDictionaryToLookupAnyAll等方法更看到這個優秀的線程:Linq - What is the quickest way to find out deferred execution or not?

我知道大多數人請使用。 AsEnumerable()或.ToList(),但哪些其他方法也適用?我可以使用.AsQueryable(),還是這是一個無操作?

它們都是不同的。賈斯汀有一個盛大的解釋。您可能還想看到:What's the difference(s) between .ToList(), .AsEnumerable(), AsQueryable()?這有一個很好的答案。


通常,您可以通過查看方法本身的名稱來理解方法的語義。名爲AsSomething的方法意味着它什麼都不做,但將輸入返回爲。這可能涉及也可能不涉及返回一個新的對象,但參考被以某種方式維護。例如,一個List<T>.AsEnumerable()只是投射到IEnumerable<T>(當然它在linq上下文中有更大的含義)。您可以將它重新投射到List<T>,並將其變爲無處不在。爲了測試它:

var list = new List<int> { 1, 2 }; 
var enum = list.AsEnumerable(); 
var newlist = enum as List<string>; 
newlist.Add(3); 
//print enum.Count() -> 3 

雖然看起來像ToSomething方法,你會得到一個完全新的對象往往轉化成別的東西。

var list = new List<int> { 1, 2 }; 
var newlist = list.ToList(); 
newlist.Add(3); 
//print list.Count -> 2 

讓我們考慮一下linq上下文之外的東西。 object.ToString()導致新的字符串表示(字符串無論如何都是不可變的,所以這有點無意義)。一個有趣的語義是List<T>.AsReadonly,它返回一個新的ReadOnlyCollection<T>實例,但是在它外面改變列表也會改變內部列表ReadOnlyCollection<T>,因此命名爲AsReadonly

var list = new List<int> { 1, 2 }; 
var readonlylist = list.AsReadonly(); 
list.Add(3); 
//print readonlylist.Count -> 3