一:一個簡單的例子html
int[] myArray = { 1, 32, 43, 343 }; IEnumerator myie = myArray.GetEnumerator(); myie.Reset(); while (myie.MoveNext()) { int i = (int)myie.Current; Console.WriteLine("Value: {0}", i); }
一般咱們這樣會這樣作:sql
foreach (int item in myArray) Console.WriteLine(item.ToString());
使用for和foreach來遍歷數組,而對於上面的語法卻用的不多,可是對foreach的具體來歷還很模糊!】數據庫
二:理解Foreach數組
要實現foreach的必需要實現IEnumerable和IEnumerator的接口,只有實現了它們,才能實現遍歷,因此要講foreach的來歷,必需要把那兩個接口給搞清楚點!post
若是對這兩個接口有了必定的瞭解後,只要實現那個GetEnumerator方法便可,而不須要實現於IEnumerable接口性能
1.IEnumerablethis
具體的做用:就是使實現這個接口的對象成爲可枚舉類型。 IEnumerable接口包含一個GetEnumerator方法,返回值爲IEnumerator的類型!代碼以下: public class MyColors : IEnumerable { string[] colors = { "Red", "Yellow", "Biue" }; public IEnumerator GetEnumerator() { return colors.GetEnumerator(); } } 那麼咱們在客戶端進行調用的時候就能夠這樣作了! MyColors colors = new MyColors(); foreach (string item in colors) Console.WriteLine(item);
數組自己就實現了IEnumerator接口,那麼兩個接口都實現了,不就好實現foreach遍歷了,其實在實現遍歷枚舉數的時候編譯器會自動去調用數組中實現枚舉數的類中的方法。url
2.IEnumerator:spa
接口的做用:實現可枚舉數,首先看一下接口的定義:.net
包含一個屬性兩個方法
MoveNext → 把當前的項移動到下一項(相似於索引值),返回一個bool值,這個bool值用來檢查當前項是否超出了枚舉數的範圍!
Current → 獲取當前項的值,返回一個object的類型
Reset → 顧名思義也就是把一些值恢復爲默認值,好比把當前項恢復到默認狀態值!
public class MyIEnumerator : IEnumerator { public MyIEnumerator(string[] colors) { this.colors = new string[colors.Length]; for (int i = 0; i < this.colors.Length; i++) this.colors[i] = colors[i]; } string[] colors; //定義一個數組,用來存儲數據 int position = -1; //定義當前項的默認值,也就是索引值,一開始認識數組的索引從「0」開始, public object Current //根據當前項獲取相應的值 { get { return colors[position]; //返回當前項的值,可是會作一個裝箱的操做! } } public bool MoveNext() //移動到下一項 { if (position < colors.Length - 1) //這就是設置默認值爲-1的根據 { position++; return true; } else { return false; } } //重置當前項的值,恢復爲默認值 public void Reset() { this.position = -1; } } 上面講到的IEnumerable接口中GetEnumerator方法是獲取要遍歷的枚舉數,在咱們沒有建立本身的遍歷枚舉數的類時,咱們使用的是Array的遍歷枚舉數的方法,
但這個有的時候不必定適合咱們,咱們須要爲本身定製一個更合適的,因此咱們要建立本身的枚舉數類(也就是上面的代碼),把第三點和第四點的代碼合併起來(改動一點代碼),以下: public class MyColors //: IEnumerable { string[] colors = { "Red", "Yellow", "Biue" }; public IEnumerator GetEnumerator() { return new MyIEnumerator(colors); } }
三、關於可枚舉和枚舉數
①可枚舉類型 → 實現IEnumerable接口,能夠不須要直接實現這個接口,但必須有個GetEnumerator方法,返回值類型必須爲IEnumerator類型,也就是第四點最後一段代碼中接口註釋的那種寫法!
②枚舉數 → 實現IEnumerator接口,實現所有方法,首先是調用GetEnumerator返回一個類型爲IEnumerator的枚舉數,而後編譯器會隱式的調用實現IEnumerator類中的方法和屬性!
總結:因此實現foreach遍歷,必須達到上面的兩種條件才能進行遍歷對象,他們能夠寫在一塊兒也能夠分開,最好是分開,進行職責分離,一個類幹一件事總歸是好事!也知足面向對象的單一指責設計原則。
下面的代碼示例演示如何實現自定義集合的 IEnumerable 和 IEnumerator 接口
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1 { public class Person { public Person(string fName, string lName) { this.firstName = fName; this.lastName = lName; } public string firstName; public string lastName; } public class People : IEnumerable { private Person[] _people; public People(Person[] pArray) { _people = new Person[pArray.Length]; for (int i = 0; i < pArray.Length; i++) { _people[i] = pArray[i]; } } IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } public PeopleEnum GetEnumerator() { return new PeopleEnum(_people); } } public class PeopleEnum : IEnumerator { public Person[] _people; // Enumerators are positioned before the first element // until the first MoveNext() call. int position = -1; public PeopleEnum(Person[] list) { _people = list; } public bool MoveNext() { position++; return (position < _people.Length); } public void Reset() { position = -1; } object IEnumerator.Current { get { return Current; } } public Person Current { get { try { return _people[position]; } catch (IndexOutOfRangeException) { throw new InvalidOperationException(); } } } } class Program { static void Main(string[] args) { Person[] peopleArray = new Person[3] { new Person("John", "Smith"), new Person("Jim", "Johnson"), new Person("Sue", "Rabon"), }; People peopleList = new People(peopleArray); foreach (Person p in peopleList) Console.WriteLine(p.firstName + " " + p.lastName); } } }
一、IList 是 ICollection 接口的子代,而且是全部非泛型列表的基接口。IList 實現有三種類別:只讀、固定大小和可變大小。沒法修改只讀 IList。固定大小的 IList 不容許添加或移除元素,但容許修改現有元素。可變大小的 IList 容許添加、移除和修改元素。
二、ICollection 接口是 System.Collections 命名空間中類的基接口。ICollection 接口擴展 IEnumerable;IDictionary 和 IList 則是擴展 ICollection 的更爲專用的接口。 IDictionary 實現是鍵/值對的集合,如 Hashtable 類。 IList 實現是值的集合,其成員可經過索引訪問,如 ArrayList 類。 某些集合(如 Queue 類和 Stack 類)限制對其元素的訪問,它們直接實現 ICollection 接口。 若是 IDictionary 接口和 IList 接口都不能知足所需集合的要求,則從 ICollection 接口派生新集合類以提升靈活性。定義全部非泛型集合的大小、枚舉器和同步方法。
三、IQueryable 提供對未指定數據 類型的特定數據源的查詢進行計算的功能,IQueryable 接口由查詢提供程序實現。 該接口只能由同時實現 IQueryable(Of T) 的提供程序實現。 若是該提供程序不實現 IQueryable(Of T),則沒法對提供程序數據源使用標準查詢運算符。 IQueryable 接口繼承 IEnumerable 接口,以便在前者表示一個查詢時能夠枚舉該查詢的結果。 枚舉強制執行與 IQueryable 對象關聯的表達式樹。 「執行表達式樹」的定義是查詢提供程序所特有的。 例如,它可能涉及將表達式樹轉換爲適用於基礎數據源的查詢語言。 在調用 Execute 方法時將執行不返回可枚舉結果的查詢。
基本概念:
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 和這幾個貨的基本原理都接近的,
就是讀取數據的時候,一個必須獨佔着數據庫的鏈接,而另外一個就是先把數據庫的的局加載到了本身本地,而後再進行操做。
使用場景模擬:
複製代碼 //IList IList users = res.ToList(); //此時已把users加載到內存,而每一個user的關聯實體(UserInfos)未 //被加載,因此下一行代碼沒法順利經過 var ss = users.Where(p => p.UserInfos.ID != 3); //此處報錯,由於P的UserInfos實體沒法被加載 // IQuerable的 IQueryable users = res.AsQueryable(); //users未被當即加載,關聯實體可經過「延遲加載」獲 //得 var ss = users.Where(p => p.UserInfos.ID != 3);//此處順利得到對應的ss
總結:
基於性能和數據一致性這兩點,使用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>