<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # [C#基礎知識系列]專題十二:迭代器 **引言:** 在C# 1.0中我們經常使用foreach來遍歷一個集合中的元素,然而**一個類型要能夠使用foreach關鍵字來對其進行遍歷必須實現IEnumerable****或IEnumerable&lt;T&gt;接口**,(之所以來必須要實現**IEnumerable**這個接口,是因為foreach是迭代語句,要使用foreach必須要有一個迭代器才行的,然而IEnumerable接口中就有**IEnumerator GetEnumerator()**方法是返回迭代器的,所以實現了**IEnumerable**接口,就必須實現GetEnumerator()這個方法來返回迭代器,有了迭代器就自然就可以使用foreach語句了),然而在C# 1.0中要獲得迭代器就必須實現**IEnumerable**接口中的****GetEnumerator()****方法,然而要實現一個迭代器就必須實現**IEnumerator**接口中的bool MoveNext()和void Reset()方法,然而 C# 2.0中提供 **yield**關鍵字來簡化迭代器的實現,這樣在C# 2.0中如果我們要自定義一個迭代器就容易多了。下面就具體介紹了C# 2.0 中如何提供對迭代器的支持. **一、迭代器的介紹** 迭代器大家可以想象成數據庫的游標,即一個集合中的某個**位置**,C# 1.0中使用foreach語句實現了訪問迭代器的內置支持,使用foreach使我們遍歷集合更加容易(比使用for語句更加方便,并且也更加容易理解),foreach被編譯后會調用GetEnumerator來返回一個迭代器,也就是一個集合中的初始位置(foreach其實也相當于是一個語法糖,把復雜的生成代碼工作交給編譯器去執行)。 **二、C#1.0如何實現迭代器** 在C# 1.0 中實現一個迭代器必須實現**IEnumerator**接口,下面代碼演示了傳統方式來實現一個自定義的迭代器: ``` 1 using System; 2 using System.Collections; 3 4 namespace 迭代器Demo 5 { 6 class Program 7 { 8 static void Main(string[] args) 9 { 10 Friends friendcollection = new Friends(); 11 foreach (Friend f in friendcollection) 12 { 13 Console.WriteLine(f.Name); 14 } 15 16 Console.Read(); 17 } 18 } 19 20 /// <summary> 21 /// 朋友類 22 /// </summary> 23 public class Friend 24 { 25 private string name; 26 public string Name 27 { 28 get { return name; } 29 set { name = value; } 30 } 31 public Friend(string name) 32 { 33 this.name = name; 34 } 35 } 36 37 /// <summary> 38 /// 朋友集合 39 /// </summary> 40 public class Friends : IEnumerable 41 { 42 private Friend[] friendarray; 43 44 public Friends() 45 { 46 friendarray = new Friend[] 47 { 48 new Friend("張三"), 49 new Friend("李四"), 50 new Friend("王五") 51 }; 52 } 53 54 // 索引器 55 public Friend this[int index] 56 { 57 get { return friendarray[index]; } 58 } 59 60 public int Count 61 { 62 get { return friendarray.Length; } 63 } 64 65 // 實現IEnumerable<T>接口方法 66 public IEnumerator GetEnumerator() 67 { 68 return new FriendIterator(this); 69 } 70 } 71 72 /// <summary> 73 /// 自定義迭代器,必須實現 IEnumerator接口 74 /// </summary> 75 public class FriendIterator : IEnumerator 76 { 77 private readonly Friends friends; 78 private int index; 79 private Friend current; 80 internal FriendIterator(Friends friendcollection) 81 { 82 this.friends = friendcollection; 83 index = 0; 84 } 85 86 #region 實現IEnumerator接口中的方法 87 public object Current 88 { 89 get 90 { 91 return this.current; 92 } 93 } 94 95 public bool MoveNext() 96 { 97 if (index + 1 > friends.Count) 98 { 99 return false; 100 } 101 else 102 { 103 this.current = friends[index]; 104 index++; 105 return true; 106 } 107 } 108 109 public void Reset() 110 { 111 index = 0; 112 } 113 114 #endregion 115 } 116 } ``` 運行結果(上面代碼中都有詳細的注釋,這里就不說明了,直接上結果截圖): ![](https://box.kancloud.cn/2016-01-23_56a2eb2bac041.png) **三、使用C#2.0的新特性簡化迭代器的實現** 在C# 1.0 中要實現一個迭代器必須實現**IEnumerator**接口,這樣就必須實現**IEnumerator**接口中的MoveNext、Reset方法和Current屬性,從上面代碼中看出,為了實現FriendIterator迭代器需要寫40行代碼,然而在C# 2.0 中通過yield return語句簡化了迭代器的實現,下面看看C# 2.0中簡化迭代器的代碼: ``` 1 namespace 簡化迭代器的實現 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 Friends friendcollection = new Friends(); 8 foreach (Friend f in friendcollection) 9 { 10 Console.WriteLine(f.Name); 11 } 12 13 Console.Read(); 14 } 15 } 16 17 /// <summary> 18 /// 朋友類 19 /// </summary> 20 public class Friend 21 { 22 private string name; 23 public string Name 24 { 25 get { return name; } 26 set { name = value; } 27 } 28 public Friend(string name) 29 { 30 this.name = name; 31 } 32 } 33 34 /// <summary> 35 /// 朋友集合 36 /// </summary> 37 public class Friends : IEnumerable 38 { 39 private Friend[] friendarray; 40 41 public Friends() 42 { 43 friendarray = new Friend[] 44 { 45 new Friend("張三"), 46 new Friend("李四"), 47 new Friend("王五") 48 }; 49 } 50 51 // 索引器 52 public Friend this[int index] 53 { 54 get { return friendarray[index]; } 55 } 56 57 public int Count 58 { 59 get { return friendarray.Length; } 60 } 61 62 // C# 2.0中簡化迭代器的實現 63 public IEnumerator GetEnumerator() 64 { 65 for (int index = 0; index < friendarray.Length; index++) 66 { 67 // 這樣就不需要額外定義一個FriendIterator迭代器來實現IEnumerator 68 // 在C# 2.0中只需要使用下面語句就可以實現一個迭代器 69 yield return friendarray[index]; 70 } 71 } 72 } 73 } ``` 在上面代碼中有一個**yield return** 語句,這個語句的作用就是告訴編譯器GetEnumerator方法不是一個普通的方法,而是實現一個迭代器的方法,當編譯器看到**yield return**語句時,編譯器知道需要實現一個迭代器,所以編譯器生成中間代碼時為我們生成了一個**IEnumerator**接口的對象,大家可以通過Reflector工具進行查看,下面是通過Reflector工具得到一張截圖: ![](https://box.kancloud.cn/2016-01-23_56a2eb2bb92de.jpg) 從上面截圖可以看出,**yield return** 語句其實是C#中提供的另一個語法糖,簡化我們實現迭代器的源代碼,把具體實現復雜迭代器的過程交給編譯器幫我們去完成,看來C#編譯器真是做得非常人性化,把復雜的工作留給自己做,讓我們做一個簡單的工作就好了。 **四、迭代器的執行過程** 為了讓大家更好的理解迭代器,下面列出迭代器的執行流程: ![](https://box.kancloud.cn/2016-01-23_56a2eb2bd5ec4.png) **五、迭代器的延遲計算** 從第四部分中迭代器的執行過程中可以知道迭代器是延遲計算的, 因為迭代的主體在MoveNext()中實現(因為在MoveNext()方法中訪問了集合中的當前位置的元素),Foreach中每次遍歷執行到in的時候才會調用MoveNext()方法,所以迭代器可以延遲計算,下面通過一個示例來演示迭代器的延遲計算: ``` namespace 迭代器延遲計算Demo { class Program { /// <summary> /// 演示迭代器延遲計算 /// </summary> /// <param name="args"></param> static void Main(string[] args) { // 測試一 //WithIterator(); //Console.Read(); // 測試二 //WithNoIterator(); //Console.Read(); // 測試三 foreach (int j in WithIterator()) { Console.WriteLine("在main輸出語句中,當前i的值為:{0}", j); } Console.Read(); } public static IEnumerable<int> WithIterator() { for (int i = 0; i < 5; i++) { Console.WriteLine("在WithIterator方法中的, 當前i的值為:{0}", i); if (i > 1) { yield return i; } } } public static IEnumerable<int> WithNoIterator() { List<int> list = new List<int>(); for (int i = 0; i < 5; i++) { Console.WriteLine("當前i的值為:{0}", i); if (i > 1) { list.Add(i); } } return list; } } } ``` 當運行測試一的代碼時,控制臺中什么都不輸出,原因是生成的迭代器延遲了**i** 值的輸出,大家可以用Reflector工具反編譯出編譯器生成的中間語言代碼就可以發現原因了,下面是一張截圖: ![](https://box.kancloud.cn/2016-01-23_56a2eb2bed423.jpg) 從圖中可以看出,WithIterator()被編譯成下面的代碼了(此時編譯器把我們自己方法體寫的代碼給改了): 從而當我們測試一的代碼中調用WithIterator()時,對于編譯器而言,就是實例化了一個**&lt;WithIterator&gt;d_0**的對象(&lt;WithIterator&gt;d_0類是編譯看到WithIterator方法中包含Yield return 語句生成的一個迭代器類),所以運行測試一的代碼時,控制臺中什么都不輸出。 當運行測試二的代碼時,運行結果就如我們期望的那樣輸出(這里的運行結果就不解釋了,列出來是為了更好說明迭代器的延遲計算): ![](https://box.kancloud.cn/2016-01-23_56a2eb2c0f5cb.jpg) 當我們運行測試三的代碼時,運行結果就有點讓我們感到疑惑了, 下面先給出運行結果截圖,然后在分析原因。 ![](https://box.kancloud.cn/2016-01-23_56a2eb2c1e3c5.jpg) 可能剛開始看到上面的結果很多人會有疑問,為什么2,3,4會運行兩次的呢?下面具體為大家分析下為什么會有這樣的結果。 測試代碼三中通過foreach語句來遍歷集合時,當運行in的時候就會運行IEnumerator.MoveNext()方法,下面是上面代碼的MoveNext()方法的代碼截圖: ![](https://box.kancloud.cn/2016-01-23_56a2eb2c31388.jpg) 從截圖中可以看到有Console.WriteLine()語句,所以用foreach遍歷的時候才會有結果輸出(主要是因為foreach中in 語句調用了MoveNext()方法),至于為什么2,3,4會運行兩行,主要是因為這里有兩個輸出語句,一個是WithIterator方法體內for語句中的輸出語句,令一個是Main函數中對WithIterator方法返回的集合進行迭代的輸出語句,在代碼中都有明確指出,相信大家經過這樣的解釋后就不難理解測試三的運行結果了。 **六、小結** 本專題主要介紹了C# 2.0中通過**yield return語句**對迭代器實現的簡化,然而對于編譯器而言,卻沒有簡化,它同樣生成了一個類去實現IEnumerator接口,只是我們開發人員去實現一個迭代器得到了簡化而已。希望通過本專題,大家可以對迭代器有一個進一步的認識,并且迭代器的延遲計算也是Linq的基礎,本專題之后將會和大家介紹C# 3.0中提出的新特性,然而C# 3.0中提出來的Lambda,Linq可以說是徹底改變我們編碼的風格,后面的專題中將會和大家一一分享我所理解C# 3.0 中的特性。 附件:源程序代碼:[http://files.cnblogs.com/zhili/%E8%BF%AD%E4%BB%A3%E5%99%A8Demo.zip](http://files.cnblogs.com/zhili/%E8%BF%AD%E4%BB%A3%E5%99%A8Demo.zip) 破解版的Reflector工具:[http://files.cnblogs.com/zhili/Reflector.zip](http://files.cnblogs.com/zhili/Reflector.zip)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看