日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

foreach原理分析

 小仙女本仙人 2021-03-15

  我們知道通常foreach可以實(shí)現(xiàn)對(duì)類(lèi)型的遍歷,但是foreach并不是針對(duì)所有類(lèi)型都可以實(shí)現(xiàn)遍歷的功能,那么我們可以思考這樣的一個(gè)問(wèn)題:foreach對(duì)類(lèi)型實(shí)施遍歷的依據(jù)條件是什么?它是通過(guò)什么方式來(lái)實(shí)現(xiàn)遍歷的?

  下面我們自定義一個(gè)類(lèi)型來(lái)嘗試使用foreach進(jìn)行遍歷,看會(huì)發(fā)生什么樣的現(xiàn)象,并且以此作為出發(fā)點(diǎn)來(lái)一點(diǎn)點(diǎn)分析foreach的原理。

1.自定義類(lèi)型并使用foreach遍歷

 運(yùn)行VS后編譯器提示了錯(cuò)誤,根據(jù)錯(cuò)誤描述可以推斷出foreach需要調(diào)用Person類(lèi)型中的”GetEnumerator”方法。

 

2.在自定義類(lèi)型中添加”GetEnumerator”方法

下一步我們根據(jù)編譯器的要求在Person類(lèi)型中添加”GetEnumerator”方法,添加該方法后又出現(xiàn)如下的錯(cuò)誤提示:

 根據(jù)編譯器的錯(cuò)誤提示,可以推斷出Person類(lèi)的GetEnumerator方法的返回值類(lèi)型必須要有MoveNext方法和Current屬性,示例中的object類(lèi)型并沒(méi)有MoveNext方法和Current屬性。

 

3.添加MoveNext方法和Current屬性

  編譯器的錯(cuò)誤提示要有MoveNext方法和Current屬性,但是我們無(wú)法搞清楚這兩個(gè)東西的具體實(shí)現(xiàn)形式,比如說(shuō)MoveNext方法的返回值是什么樣的?Current屬性是只讀還是可讀可寫(xiě)的?

  此時(shí)我們可以去已經(jīng)支持foreach的類(lèi)型中查找GetEnumerator方法返回值類(lèi)型,并對(duì)該類(lèi)型的實(shí)現(xiàn)進(jìn)行仿寫(xiě)并用于我們自定義類(lèi)型當(dāng)中。string類(lèi)型作為常用類(lèi)型并支持foreach遍歷,下面我們查看該string的GetEnumerator方法返回值類(lèi)型進(jìn)行仿寫(xiě)。

仿寫(xiě)后編譯通過(guò):


 以“數(shù)數(shù)”的思想來(lái)真正實(shí)現(xiàn)foreach遍歷的功能

  在生活中小朋友們往往通過(guò)數(shù)數(shù)的形式來(lái)完成對(duì)數(shù)學(xué)的啟蒙,foreach遍歷的思想就類(lèi)似于“數(shù)數(shù)”。小朋友數(shù)數(shù)往往需要通過(guò)雙手來(lái)對(duì)事物進(jìn)行數(shù)數(shù),這就相當(dāng)于GetEnumerator方法:其作用實(shí)際上是需要foreach當(dāng)前遍歷的類(lèi)型調(diào)用該方法提供一個(gè)用于遍歷當(dāng)前的類(lèi)型的“迭代計(jì)數(shù)器對(duì)象”,GetEnumerator方法的返回值類(lèi)型:該類(lèi)型其實(shí)就是用于foreach遍歷當(dāng)前類(lèi)型的“迭代計(jì)數(shù)器對(duì)象”,類(lèi)似于計(jì)數(shù)的雙手(工具);Current屬性:就相當(dāng)于當(dāng)前數(shù)到的對(duì)象(foreach遍歷到的當(dāng)前元素);MoveNext方法:就相當(dāng)于“數(shù)數(shù)”中對(duì)元素不斷的移動(dòng)的動(dòng)作,促使讓“迭代計(jì)數(shù)器對(duì)象”的計(jì)數(shù)移至到下一位。

  到目前為止已經(jīng)提供了編譯器錯(cuò)誤提示的所有成員,但實(shí)際運(yùn)行是毫無(wú)意義的,因?yàn)橥ǔ>幊讨袑?shí)現(xiàn)遍歷的對(duì)象都是一個(gè)序列,但是目前示例中Person類(lèi)型并不是且成員未包含序列。我們將為示例中Person類(lèi)型添加一個(gè)序列,作為foreach“遍歷的對(duì)象”。


 實(shí)現(xiàn)“數(shù)數(shù)的功能”

1.遍歷的數(shù)據(jù)對(duì)象

  添加foreach“遍歷的數(shù)據(jù)對(duì)象”后又有問(wèn)題來(lái)了,foreach如何訪問(wèn)到這個(gè)數(shù)據(jù)呢。我們可以將數(shù)據(jù)作為“迭代計(jì)數(shù)器對(duì)象”構(gòu)造函數(shù)的參數(shù)在GetEnumerator方法中傳遞過(guò)去,然后“迭代計(jì)數(shù)器對(duì)象”中提供一個(gè)字段進(jìn)行存儲(chǔ)。

 

2.設(shè)置foreach遍歷到的當(dāng)前元素(Current屬性)

  目前我們遍歷的“對(duì)象”是一個(gè)string數(shù)組,所以要讀取這個(gè)數(shù)組里的元素,我們需要一個(gè)下標(biāo)索引來(lái)讀取遍歷到的當(dāng)前元素,并作為Current屬性值。下面我們將設(shè)置一個(gè)int類(lèi)型值為-1的字段作為“讀取下標(biāo)”,然后在Current屬性的get方法中通過(guò)下標(biāo)索引器讀取“當(dāng)前遍歷到的數(shù)據(jù)對(duì)象”。

 

3.MoveNext方法

  因?yàn)槲覀兪峭ㄟ^(guò)下標(biāo)去訪問(wèn)元素的,所以需要對(duì)下標(biāo)進(jìn)行遞增進(jìn)行變化,從而不斷指向下一個(gè)元素從而到達(dá)累計(jì)。MoveNext方法是一個(gè)布爾的返回值類(lèi)型,其主要目的是告知foreach當(dāng)前遍歷的數(shù)據(jù)對(duì)象是否還存在沒(méi)有遍歷到的元素,如果存在元素則不斷遞增下標(biāo)索引并反會(huì)true,反之返回false并結(jié)束遍歷,MoveNext方法的返回值相當(dāng)于foreach遍歷的前提條件。

  下面我們通過(guò)代碼來(lái)實(shí)現(xiàn)MoveNext方法:

 

到目前為止我們已經(jīng)將一個(gè)不具備foreach條件的自定義類(lèi)型,通過(guò)自編碼實(shí)現(xiàn)了foreach的基本要求。下面我們通過(guò)代碼運(yùn)行看看執(zhí)行結(jié)果:

結(jié)果運(yùn)行成功,并打印輸出遍歷的數(shù)據(jù)對(duì)象(Person中的數(shù)組)。

注意:遍歷該數(shù)組我們并沒(méi)有通過(guò)foreach直接對(duì)其進(jìn)行的遍歷,而是結(jié)合foreach的流程本質(zhì)和基本要求來(lái)實(shí)現(xiàn)的遍歷功能。


 通過(guò)調(diào)試來(lái)分析foreach的遍歷的原理

 通過(guò)調(diào)試結(jié)果我們可以總結(jié)下foreach遍歷主要依靠三個(gè)流程:

  1. foreach調(diào)用當(dāng)前遍歷類(lèi)型的GetEnumerator方法創(chuàng)建一個(gè)“迭代計(jì)數(shù)器對(duì)象”,并將遍歷的數(shù)據(jù)作為參數(shù)傳遞到對(duì)象構(gòu)造函數(shù)中。(獲取迭代計(jì)數(shù)器對(duì)象)
  2. “迭代計(jì)數(shù)器對(duì)象”調(diào)用MoveNext方法將索引下標(biāo)遞增(第一次遞增為0),如果遞增下標(biāo)大于數(shù)組長(zhǎng)度則代表已經(jīng)遍歷完。(調(diào)用MoveNext方法)
  3. MoveNext方法返回true,代表還有元素需要遍歷,使用當(dāng)前下標(biāo)在數(shù)據(jù)中獲取元素并設(shè)置為Current屬性值。(獲取Current屬性)

 基于foreach的原理思想,我們還可以將遍歷寫(xiě)成如下形式:

foreach的寫(xiě)法其實(shí)就是調(diào)用上面的代碼片段,從而實(shí)現(xiàn)的一種“語(yǔ)法糖”。


C#中基于原理的實(shí)現(xiàn)方式

  在上文中我們借鑒string類(lèi)型中的GetEnumerator方法來(lái)參照實(shí)現(xiàn)“迭代計(jì)數(shù)器對(duì)象”當(dāng)中的MoveNext方法和Current屬性。

 

  在.net中看某個(gè)類(lèi)型是否支持使用foreach進(jìn)行遍歷,其實(shí)接可以看該類(lèi)型和該類(lèi)型的“迭代計(jì)數(shù)器”是否都實(shí)現(xiàn)了IEnumerable接口。IEnumerable接口中的成員就包含了foreach實(shí)現(xiàn)的原理和需要調(diào)用的成員。

圖一:

 圖二:

 


 

示例源碼

 1   class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5           
 6             Person person = new Person();
 7             foreach (var item in person)
 8             {
 9                 Console.WriteLine(item);
10             }
11 
12             var Enumerator = person.GetEnumerator();
13             while (Enumerator.MoveNext())
14             {
15                 Console.WriteLine(Enumerator.Current);
16             }
17 
18         }  // END Main()
19 
20     }
Main

 

 1    class Person
 2     {
 3         string[] Datas = new string[] { "張三","李四","王五"};
 4 
 5         public PersonEnumerator GetEnumerator()
 6         {
 7             return new PersonEnumerator(Datas);
 8         }
 9     }
10 
11     /// <summary>
12     /// 迭代計(jì)數(shù)器
13     /// </summary>
14     class PersonEnumerator
15     {
16         public PersonEnumerator(string[] datas) { this.Datas = datas; }
17 
18         /// <summary>
19         /// 遍歷的數(shù)據(jù)對(duì)象
20         /// </summary>
21         private string[] Datas;
22 
23         private int index = -1;
24 
25         /// <summary>
26         /// 當(dāng)前遍歷到的元素
27         /// </summary>
28         public string Current {
29             get { return Datas[index]; }
30         }
31 
32         /// <summary>
33         /// 將記錄指針移至下一條
34         /// </summary>
35         /// <returns>是否存在尚未遍歷的元素</returns>
36         public bool MoveNext()
37         {
38             index++;
39             return index < Datas.Length;
40         }
41 
42     }
Model

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多