LINQ查詢方法一共提供了兩種擴展方法,在System.Linq命名空間下,有兩個靜態類:Enumerable類,它針對繼承了IEnumerable<T>接口的集合進行擴展;Queryable類,針對繼承了IQueryable<T>接口的集合進行擴展。咱們會發現接口IQueryable<T>實際也是繼承了IEnumerable<T>接口的,既然這樣微軟爲何要設計出兩套擴展方法呢?sql
從LINQ查詢功能上咱們知道實際上能夠分爲三類:LINQ to OBJECTS、LINQ to SQL和LINQ to XML。其實微設計這兩套接口主要是針對LINQ to OBJECTS和LINQ to SQL,二者對於查詢的內部處理機制是徹底不一樣的。針對LINQ to OBJECTS 時,使用Enumerable中的擴展方法對本地集合進行排序和查詢操做,查詢參數接受的是Func<>,Func<>叫作謂語表達式,至關於一個委託。針對LINQ to SQL時,則使用Queryable中的擴展方法,它接受的是Expression<>。數據庫
那麼,到底何時使用IQueryable<T>,何時使用IEnumerable<T>?spa
首先咱們來看一下LINQ to SQL的代碼:設計
using (var context = new NorthwindEntities()) 3d { blog var orderTmp = context.Orders.Where(p=>p.CustomerID=="RATTC"); 排序 var orders = orderTmp.Where(p => p.OrderDate > new DateTime(1997, 1, 1)); 繼承 foreach (var order in orders) 接口 { 編譯器 Console.WriteLine("OrderId:" + order.OrderID); } } |
經過vs的Intellisense咱們能夠看到Where的返回類型爲IQueryable,參數是Expression類型的:
咱們再看一下這一段代碼:
using (var context = new NorthwindEntities()) { var orderTmp = context.Orders.Where(p => p.CustomerID == "RATTC").AsEnumerable(); var orders = orderTmp.Where(p => p.OrderDate > new DateTime(1997, 1, 1)); foreach (var order in orders) { Console.WriteLine("OrderId:" + order.OrderID); } } |
這段代碼的不一樣在於咱們將LINQ的查詢返回IEnumerable類型,咱們看一下vs的Intellisense效果:
因爲咱們在LINQ查詢的時候加上了AsEnumerable(),所以咱們在第二條語句能看到返回類型已經變爲IEnumerable,參數也變成了Func<>類型。
至於這兩段代碼到底有什麼區別,咱們分別執行代碼,在sql profiler裏看一下生成的sql語句:
第一段代碼效果:
雖然咱們使用兩條語句進行了查詢,但最終只生成了一條SQL語句,將查詢參數合併了。
第二代碼效果:
這一次咱們依然只看到一條SQL語句,但查詢條件也只有一個,但兩次查詢的結果是一致。
緣由在於Func<>直接會被編譯器編譯成IL代碼,可是Expression<>只是存儲了一個表達式樹,在運行期做處理,LINQ to SQL最終會將表達式樹轉爲相應的SQL語句,而後在數據庫中執行。
如今咱們應該知道什麼時候使用IEnumerable<T>,什麼時候使用Iqueryable<T>。
以上內容部分參考《編寫高質量代碼改善C#程序的157個建議》。