[转]那些年我还不懂:IList,ICollection,IEnumerable,IEnumerator,IQueryable
1、首先看一個簡單的例子
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);} 相信很多人都不會像上面這樣去遍歷myArray這個數組,通常我們這樣會這樣做 foreach (int item in myArray)Console.WriteLine(item.ToString()); 在大部分的情況下,很多人會使用for和foreach來遍歷數組,而對于上面的語法卻用的很少,但是對foreach的具體來歷還很模糊! 2、理解foreach大家都知道要實現foreach的必須要實現IEnumerable和IEnumerator的接口,只有實現了它們,才能實現遍歷,所以要講foreach的來歷,必須要把那兩個接口給搞清楚點!
這邊也想說明一點的是:如果對這兩個接口有了一定的了解后,只要實現那個GetEnumerator方法即可,而不需要實現于IEnumerable接口,這只是針對對這兩個接口有一定了解的朋友!
2.1 IEnumerable
具體的作用:就是使實現這個接口的對象成為可枚舉類型。
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); 這樣就能使用實現這個接口的對象進行foreach遍歷了,就是這么簡單的一個列子,這邊可能有的人會有疑問,我們就實現了IEnumerable接口但卻沒實現IEnumerator接口,可是我們不是說只有實現了這兩個接口才可以進行foreach遍歷嗎?可以這樣說當使用forach進行遍歷的時候,編譯器會到這個對象的類中去尋找GetEnumerator方法,找到這個方法后返回這個一個IEnumerator的對象(枚舉數),而我這邊返回的是“colors.GetEnumerator()”,是一個數組對象調用它本身中的“GetEnumerator”方法,所以說數組本身就實現了IEnumerator接口,那么兩個接口都實現了,不就好實現foreach遍歷了,其實在實現遍歷枚舉數的時候編譯器會自動去調用數組中實現枚舉數的類中的方法。 2.2 IEnumerator接口的作用:實現可枚舉數,首先看一下接口的定義:
包含一個屬性兩個方法
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”開始,//怎么默認設置他為“-1”呢,最后才想明白,這樣設置是合情合理的!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);}} 3、關于可枚舉類型和枚舉數①可枚舉類型 → 實現IEnumerable接口,可以不需要直接實現這個接口,但必須有個GetEnumerator方法,返回值類型必須為IEnumerator類型,也就是第四點最后一段代碼中接口注釋的那種寫法!
②枚舉數 → 實現IEnumerator接口,實現全部方法,首先是調用GetEnumerator返回一個類型為IEnumerator的枚舉數,然后編譯器會隱式的調用實現IEnumerator類中的方法和屬性!
?
總結:所以實現foreach遍歷,必須達到上面的兩種條件才能進行遍歷對象,他們可以寫在一起也可以分開,最好是分開,進行職責分離,一個類干一件事總歸是好事!也滿足面向對象的單一指責設計原則。
?
下面的代碼示例演示如何實現自定義集合的 IEnumerable 和 IEnumerator 接口(代碼來自MSDN)
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,IQueryable
?
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 方法時將執行不返回可枚舉結果的查詢。
轉載于:https://www.cnblogs.com/colder/p/4188354.html
總結
以上是生活随笔為你收集整理的[转]那些年我还不懂:IList,ICollection,IEnumerable,IEnumerator,IQueryable的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: return view详解
- 下一篇: eclipse环境的搭建以及JDK的安装