成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

詳解 C# 的 foreach 工作原理

原創
開發 后端
作為開發人員我們經常會在程序中編寫 foreach 語句實現對類型的遍歷,但是并不是所有的類型都可以遍歷,這個知識點是絕大部分開發成員所知曉的。但是類型可以被 foreach 遍歷的依據是什么部分程序員并不清楚,下面我就通過舉例的方式來具體講解 foreach 原理。

[[346581]]

【51CTO.com原創稿件】作為開發人員我們經常會在程序中編寫 foreach 語句實現對類型的遍歷,但是并不是所有的類型都可以遍歷,這個知識點是絕大部分開發成員所知曉的。但是類型可以被 foreach 遍歷的依據是什么部分程序員并不清楚,下面我就通過舉例的方式來具體講解 foreach 原理。

在這里我們首先自定義一個類型 Cat 并遍歷這個類型:

  1. //定義 Cat 類型 
  2. class Cat 
  3. //遍歷 Cat 
  4. class Program 
  5.    static void Main(string[] args) 
  6.   { 
  7.        Cat cat = new Cat(); 
  8.        foreach(var item in cat) 
  9.       { 
  10.            //more code 
  11.       } 
  12.   } 

我們運行上述代碼后編譯器會提示錯誤 “Cat” 不包含 “GetEnumerator” 的公共定義,因此 foreach 語句不能作用于 “Cat” 類型的變量,由此錯誤提示我們可以得知如果 Cat 類型可以被 foreach 遍歷,那么 Cat 類就必須實現 GetEnumerator 方法。下面我們就在 Cat 類中加入 GetEnumerator 方法。

  1. class Cat 
  2.    //加入 GetEnumerator 方法的實現 
  3.    public object GetEnumerator() 
  4.   { 
  5.        return null
  6.   } 

我們再次運行代碼,這時程序出現如下兩個錯誤提示:

  • foreach 要求 “Cat.GetEnumerator()”的返回類型 “object”必須具有適當的公共 MoveNext 方法和公共 Current 屬性;

  • object 并不包含 “MoveNext” 的定義。

根據上述錯誤提示我們可以推斷出 GetEnumerator 方法的返回值必須要有 MoveNext 方法和 Current 屬性。但是我們目前并不知道 GetEnumerator 方法的返回值類型和 Current 屬性是否是只讀的,這種情況我們該怎么辦呢?此時我們可以查看已經支持 foreach 遍歷的類型是怎么做的,下面的代碼段展示了 string 類型是如何實現的(只列出了關鍵代碼)。

  1. //more code 
  2. public CharEnumerator GetEnumerator(); 
  3. //more code 
  4. pubic sealed class CharEnumerator:ICloneabe,IEnumerator<char>,IEnumerator,IDisposable 
  5.    public char Current {get;} 
  6.    //more code 
  7.    public bool MoveNext(); 
  8.    //more code 

根據上述代碼段我們仿寫如下:

  1. class Cat 
  2.    public CatEnumerator GetEnumerator() 
  3.   { 
  4.        return new CatEnumerator(); 
  5.   } 
  6. class CatEnumerator 
  7.    public char Current {get;} 
  8.    public bool MoveNext() 
  9.   { 
  10.        return true
  11.   } 

這時我們編譯發現原來的錯誤已經消失了,程序編譯通過了。但是不要以為到這里就完了,Cat 類僅僅包含這些是沒有任何意義的,這些內容只是為了讓程序通過編譯而已,在實際開發中我們遍歷的對象是一個序列,那么我們現在就在 Cat 類中添加一個固定的序列:

  1. class Cat 
  2.    string[] datas=new string[]{"波斯貓","貍花貓","無毛貓","虎斑貓"}; 
  3.    public CatEnumerator GetEnumerator() 
  4.   { 
  5.        return new CatEnumerator(); 
  6.   } 

我們已經添加了數據對象,那么 foreach 是如何訪問到這個數據的呢?這時我們可以將數據對象通過 GetEnumerator 方法作為迭代計數器對象(CatEnumerator)構造函數的參數傳遞進去,然后迭代計數器對象提供一個屬性將這些數據存儲起來。

  1. class Cat 
  2.    string[] datas=new string[]{"波斯貓","貍花貓","無毛貓","虎斑貓"}; 
  3.    public CatEnumerator GetEnumerator() 
  4.   { 
  5.        return new CatEnumerator(datas); 
  6.   } 
  7. class CatEnumerator 
  8.    //存儲數據 
  9.    private string[] datas; 
  10.    //帶參構造函數 
  11.    public CatEnumerator(string[] datas) 
  12.   { 
  13.        this.datas=datas; 
  14.   } 
  15.    public char Current {get;} 
  16.    public bool MoveNext() 
  17.   { 
  18.        return true
  19.   } 

到目前為止我們已經設置了遍歷的數據,如果要將數據遍歷出來還需要一個下標索引來讀取數組中的每個元素,并將每次讀取出來的元素值賦值給 Current 屬性。我們可以在迭代計數器對象中定義一個 index 整型私有屬性作為下標索引屬性,這里需要注意的是我們 index 這個屬性的默認值為 -1 ,這一點是很多新手開發人員比較容易出錯的地方。既然有下標了,我們在遍歷的時候下標就必須是遞增變化,不斷指向下一個元素的位置直到到達數組的末端為止。這時我們就需要在 MoveNext 方法中進行執行下標遞增的操作了,MoveNext 方法是一個返回值為 bool 類型的方法,其目的是告知 foreach 當前遍歷的數據對象是否存在還未遍歷到的元素,如果存在就返回 true 反之返回 false 遍歷結束。下面我們針對這一段所說的內容進行代碼編寫。

  1. class CatEnumerator 
  2.    //存儲數據 
  3.    private string[] datas; 
  4.    //帶參構造函數 
  5.    public CatEnumerator(string[] datas) 
  6.   { 
  7.        this.datas=datas; 
  8.   } 
  9.    //數組下標 
  10.    private int index=-1; 
  11.    //遍歷當前元素 
  12.    public char Current  
  13.   { 
  14.        get 
  15.       { 
  16.            return datas[index]; 
  17.       } 
  18.   } 
  19.    public bool MoveNext() 
  20.   { 
  21.        index++; 
  22.        return index < datas.Length; 
  23.        return true
  24.   } 

到目前為止我們就編寫了一個可以通過 foreach 遍歷的類型,這里有三點很重要:

  • GetEnumerator 方法的作用是 foreach 調用當前需要遍歷的類型的迭代計數器對象,該方法的返回類型為用于foreach 遍歷的迭代計數器對象;

  • Current 屬性就是當前遍歷到的對象;

  • MoveNext 方法促使迭代計數器對象的計數移動到下一位。

通過前面所述的內容,我們可知 foreach 遍歷主要有三個步驟:

  • foreach 調用當前可遍歷類型的 GetEnumerator 方法創建一個迭代計數器對象,并將要遍歷的數據傳遞給迭代計數器對象的構造函數中;

  • 迭代計數器對象調用它 MoveNext 方法將所以小標遞增 1 ,若下標大于數據長度則迭代完成;

  • MoveNext 方法返回 true 并返回 Current 屬性中存儲的數據。

以上三個步驟總結起來就是 獲取迭代計數器對象 >> 調用 MoveNext 方法 >> 獲取 Current 屬性。

小技巧:在 c# 中如果要查看某個類型是否支持 foreach 我們可以查看該類型和該類型的迭代計數器是否都實現了 IEnumerable 接口,因為 IEnumerable 接口中的就包含了 foreach 實現的原理和必須調用的成員。

作者簡介

朱鋼,筆名喵叔,國內某技術博客認證專家,.NET高級開發工程師,7年一線開發經驗,參與過電子政務系統和AI客服系統的開發,以及互聯網招聘網站的架構設計,目前就職于一家初創公司,從事企業級安全監控系統的開發。

【51CTO原創稿件,合作站點轉載請注明原文作者和出處為51CTO.com】

 

責任編輯:龐桂玉 來源: 51CTO
相關推薦

2009-07-31 18:39:31

C#中foreach引

2009-08-28 17:18:55

foreach循環

2011-03-11 09:41:17

JavaGC

2009-01-19 10:26:02

C#Namespace.NET

2009-08-31 16:47:39

C#接口的定義

2025-05-08 08:10:53

2009-09-03 17:40:25

C#發送短信

2009-07-30 18:20:21

C#繼承

2009-08-24 11:23:41

C# TimeLabe

2009-09-01 16:07:04

C#命名規約

2009-09-07 16:13:56

C# MessageB

2009-08-14 17:09:48

C#引用類型

2009-09-02 19:12:37

C#遞歸

2009-09-02 11:02:57

C#動態數組

2009-08-13 14:46:03

C#結構體定義

2009-09-16 13:05:32

C#組件開發

2009-09-17 16:34:24

C#組件類

2009-08-26 15:25:06

.NET Framew

2009-08-25 17:43:17

C#串口監聽

2009-07-09 14:01:22

JVM工作原理
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 中文字幕在线剧情 | 一区二区三区视频在线 | 久久er99热精品一区二区 | 国产美女一区二区 | 一区二区三区不卡视频 | 一级毛片色一级 | 国产日韩欧美一区二区 | 天堂av在线影院 | 国产一区二区 | 一区二区三区四区在线视频 | 欧美不卡 | 日本大片在线播放 | 亚洲二区在线 | 一区二区三区中文字幕 | 午夜视频在线 | 日韩免费网站 | 国产98色在线 | 日韩 | 日韩一级二级片 | 久久视频精品 | www精品 | 精品在线播放 | 久草网址 | 欧美h视频 | 成人精品视频在线 | 久久天堂 | 国产成人网 | 韩日av片 | 91久久国产综合久久 | 国产欧美一区二区三区国产幕精品 | 国产片一区二区三区 | 久久一起草 | 宅女噜噜66国产精品观看免费 | 成人国内精品久久久久一区 | 久久大陆 | 最新免费黄色网址 | 国产精品国产精品国产专区不卡 | 久久久黑人 | 亚洲精品一区二区三区在线 | 亚洲国产黄| 97伦理电影网 | 午夜影院在线观看 |