C#中IEnumerable、ICollection、IList、IQueryable 、List之間的區別
一:一個簡單的例子
1 2 3 4 5 6 7 8 |
while (myie.MoveNext())
Console.WriteLine( "Value: {0}" , i);
|
通常我們這樣會這樣做:
1 2 |
|
使用for和foreach來遍歷陣列,而對於上面的語法卻用的很少,但是對foreach的具體來歷還很模糊!】
二:理解Foreach
要實現foreach的必須要實現IEnumerable和IEnumerator的介面,只有實現了它們,才能實現遍歷,所以要講foreach的來歷,必須要把那兩個介面給搞清楚點!
如果對這兩個介面有了一定的瞭解後,只要實現那個GetEnumerator方法即可,而不需要實現於IEnumerable介面
1.IEnumerable
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
陣列本身就實現了IEnumerator介面,那麼兩個介面都實現了,不就好實現foreach遍歷了,其實在實現遍歷列舉數的時候編譯器會自動去呼叫陣列中實現列舉數的類中的方法。
2.IEnumerator:
介面的作用:實現可列舉數,首先看一下介面的定義:
包含一個屬性兩個方法
MoveNext → 把當前的項移動到下一項(類似於索引值),返回一個bool值,這個bool值用來檢查當前項是否超出了列舉數的範圍!
Current → 獲取當前項的值,返回一個object的型別
Reset → 顧名思義也就是把一些值恢復為預設值,比如把當前項恢復到預設狀態值!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
|
3、關於可列舉和列舉數
①可列舉型別 → 實現IEnumerable介面,可以不需要直接實現這個介面,但必須有個GetEnumerator方法,返回值型別必須為IEnumerator型別,也就是第四點最後一段程式碼中介面註釋的那種寫法!
②列舉數 → 實現IEnumerator介面,實現全部方法,首先是呼叫GetEnumerator返回一個型別為IEnumerator的列舉數,然後編譯器會隱式的呼叫實現IEnumerator類中的方法和屬性!
總結:所以實現foreach遍歷,必須達到上面的兩種條件才能進行遍歷物件,他們可以寫在一起也可以分開,最好是分開,進行職責分離,一個類幹一件事總歸是好事!也滿足面向物件的單一指責設計原則。
下面的程式碼示例演示如何實現自定義集合的 IEnumerable 和 IEnumerator 介面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
|
1、IList 是 ICollection 介面的子代,並且是所有非泛型列表的基介面。IList 實現有三種類別:只讀、固定大小和可變大小。無法修改只讀 IList。固定大小的 IList 不允許新增或移除元素,但允許修改現有元素。可變大小的 IList 允許新增、移除和修改元素。
2、ICollection 介面是 System.Collections 名稱空間中類的基介面。ICollection 介面擴充套件 IEnumerable;IDictionary 和 IList 則是擴充套件 ICollection 的更為專用的介面。 IDictionary 實現是鍵/值對的集合,如 Hashtable 類。 IList 實現是值的集合,其成員可通過索引訪問,如 ArrayList 類。 某些集合(如 Queue 類和 Stack 類)限制對其元素的訪問,它們直接實現 ICollection 介面。 如果 IDictionary 介面和 IList 介面都不能滿足所需集合的要求,則從 ICollection 介面派生新集合類以提高靈活性。定義所有非泛型集合的大小、列舉器和同步方法。
3、IQueryable 提供對未指定資料 型別的特定資料來源的查詢進行計算的功能,IQueryable 介面由查詢提供程式實現。 該介面只能由同時實現 IQueryable(Of T) 的提供程式實現。 如果該提供程式不實現 IQueryable(Of T),則無法對提供程式資料來源使用標準查詢運算子。 IQueryable 介面繼承 IEnumerable 介面,以便在前者表示一個查詢時可以列舉該查詢的結果。 列舉強制執行與 IQueryable 物件關聯的表示式樹。 “執行表示式樹”的定義是查詢提供程式所特有的。 例如,它可能涉及將表示式樹轉換為適用於基礎資料來源的查詢語言。 在呼叫 Execute 方法時將執行不返回可列舉結果的查詢。
IQueryable和IEnumberable and IList與Lis t區別
基本概念: IEnumerable:使用的是LINQ to Object方式,它會將AsEnumerable()時對應的所有記錄都先載入到記憶體,然後在此基礎上再執行後來的Query IQeurable(IQuerable<T>):不在記憶體載入持久資料,因為這傢伙只是在組裝SQL,(延遲執行) 到你要使用的時候, 例如 list.Tolist() or list.Count()的時候,資料才從資料庫進行載入 (AsQueryable())。 IList(IList<T>):泛型介面是 ICollection 泛型介面的子代,作為所有泛型列表的基介面, 在用途方面如果作為資料集合的載體這是莫有問題的,只是如果需要對集合做各種的操作,例如 排序 編輯 統計等等,它不行。 List <> :泛型類,它已經實現了IList <> 定義的那些方法,IList<T> list=new List<T>(); 只是想建立一個基於介面IList<Class1>的物件的例項,這個介面是由List<T>實現的。只是希望使用到IList<T>介面規定的功能而已
抽象場景: 其實在我們之前沒有使用 ORM 的的很久很久以前,我們 在ADO.net 裡面使用的 DataReader 和 DataAdapter or DataSet 和這幾個貨的基本原理都接近的, 就是讀取資料的時候,一個必須獨佔著資料庫的連線,而另一個就是先把資料庫的的局載入到了自己本地,然後再進行操作。
使用場景模擬:
1 2 3 4 5 6 7 8 9 10 |
|
總結:
基於效能和資料一致性這兩點,使用IQueryable時必須謹慎,而在大多數情況下我們應使用IList。
1.當你打算馬上使用查詢後的結果(比如迴圈作邏輯處理或者填充到一個table/grid中),
並且你不介意該查詢即時被執行後的結果可以供呼叫者(Consummer)作後續查詢(比如這是一個"GetAll"的方法),或者你希望該查執行,使用ToList()
2.當你希望查詢後的結果可以供呼叫者(Consummer)作後續查詢(比如這是一個"GetAll"的方法),或者你希望該查詢延時執行,使用AsQueryable()
3.按照功能由低到高:List<T> IList<T> IQueryable<T> IEnumerable<T>
4.按照效能由低到高:IEnumerable<T> IQueryable<T> IList<T> List<T>