C#學習之用迭代器實現枚舉器


本人初學C#,本文僅供個人整理思路用,那里說得不對,請大家多多指教,萬分感激!

上一篇文章為自定義類實現了foreach的功能,但實現過程中要實現IEnumerator接口(包括MoveNext、Reset函數和Current屬性)以便GetEnumerator函數能獲取枚舉數,有點復雜,有點繁瑣。

已經知道:主要一個類實現了GetEnumerator函數就能foreach,而實現IEnumerator接口只是實現GetEnumerator函數的其中一個辦法,也就說還有其他辦法實現GetEnumerator函數了?是的,C#2.0為我們提供了一種很簡單的方法來實現GetEnumerator函數,那就是使用迭代器!(還記得吧,C#里的迭代器和C++里的是不同的)

下面是來自MSDN的解說:

 

迭代器概述

  • 迭代器是可以返回相同類型的值的有序序列的一段代碼。

  • 迭代器可用作方法、運算符或 get 訪問器的代碼體。

  • 迭代器代碼使用 yield return 語句依次返回每個元素。yield break 將終止迭代。有關更多信息,請參見 yield

  • 可以在類中實現多個迭代器。每個迭代器都必須像任何類成員一樣有唯一的名稱,並且可以在 foreach 語句中被客戶端代碼調用,如下所示:foreach(int x in SampleClass.Iterator2){}

  • 迭代器的返回類型必須為 IEnumerableIEnumeratorIEnumerable<T> 或 IEnumerator<T>。

yield 關鍵字用於指定返回的值。到達 yield return 語句時,會保存當前位置。下次調用迭代器時將從此位置重新開始執行。

 

第一部分:使用默認迭代器實現獲取枚舉數

1、定義Person類

View Code
 1     public class Person
2 {
3 public string Name;
4 public int Age;
5
6 public Person(string name, int age)
7 {
8 Name = name;
9 Age = age;
10 }
11
12 public override string ToString()
13 {
14 return "Name: " + Name + "\tAge: " + Age;
15 }
16 }

 

2、定義PeopleEnum1類,里面實現了GetEnumerator函數(也就是迭代器了,這是默認的迭代器),但實現的過程相對於上一篇文章里介紹的實現過程要簡單很多,這就是yield的功效。yield的實現原理這里就不詳說了,可以概括為:GetEnumerator函數里的迭代塊把 IEnumerator接口的MoveNext、Reset方法和Current屬性封裝了,但本質沒變,只是我們使用起來更方便了。

 1     public class PeopleEnum1
2 {
3 private Person[] _perple;
4
5 //構造函數
6 public PeopleEnum1(Person[] list)
7 {
8 _perple = new Person[list.Length];
9 for (int i = 0; i < list.Length; i++)
10 {
11 _perple[i] = list[i];
12 }
13 }
14
15 public IEnumerator GetEnumerator()
16 {
17 for (int i = 0; i < _perple.Length; i++)
18 {
19 yield return _perple[i];
20 }
21 }
22
23 }

 

3、主函數代碼

View Code
 1     class Program
2 {
3 static void Main(string[] args)
4 {
5 Person[] persons = new Person[]
6 {
7 new Person("aaa", 20),
8 new Person("bbb", 21),
9 new Person("ccc", 22)
10 };
11
12 PeopleEnum1 peopleEnum = new PeopleEnum1(persons);
13
14 foreach (var item in peopleEnum)
15 {
16 System.Console.WriteLine(item);
17
18 }
19
20 System.Console.ReadKey();
21 }
22 }

運行,成功,嘿嘿

 

第二部分:自定義迭代器

 第一部分用默認迭代器GetEnumerator 實現了類的foreach,我們也可以定義自己的迭代器來獲取自己想要的枚舉數。比較說,我想列舉出類中未成年人的信息,默認的迭代器無能為力,該怎么實現自定義的迭代器呢?

1、為PeopleEnum1類添加一個迭代器 GetChildren ,在這里,這個迭代器是一個屬性,也可以定義為函數。對於類中的元素,只有Age 小於18的元素才 yield return ,其他的不要。

View Code
 1     public class PeopleEnum1
2 {
3 private Person[] _perple;
4
5 //構造函數
6 public PeopleEnum1(Person[] list)
7 {
8 _perple = new Person[list.Length];
9 for (int i = 0; i < list.Length; i++)
10 {
11 _perple[i] = list[i];
12 }
13 }
14
15 //默認的迭代器?
16 public IEnumerator GetEnumerator()
17 {
18 for (int i = 0; i < _perple.Length; i++)
19 {
20 yield return _perple[i];
21 }
22 }
23
24
25 //自定義迭代器
26 public IEnumerable GetChildren
27 {
28 get
29 {
30 for (int i = 0; i < _perple.Length; i++)
31 {
32 if (_perple[i].Age < 18)
33 {
34 yield return _perple[i];
35 }
36 }
37 }
38 }
39 }

 

 2、主函數代碼

View Code
 1     class Program
2 {
3 static void Main(string[] args)
4 {
5 Person[] persons = new Person[]
6 {
7 new Person("aaa", 16),
8 new Person("bbb", 18),
9 new Person("ccc", 22)
10 };
11
12
13 PeopleEnum1 peopleEnum = new PeopleEnum1(persons);
14
15 foreach (var item in peopleEnum)
16 {
17 System.Console.WriteLine(item);
18 }
19
20
21 Console.WriteLine("\n集合中未成年人的信息");
22
23 foreach (var item in peopleEnum.GetChildren)
24 {
25 Console.WriteLine(item);
26 }
27
28 System.Console.ReadKey();
29 }
30 }

 

輸出結果:

可以看到,自定義的迭代器 GetChildren 成功foreach了。

 

注意:默認迭代器 GetEnumerator 的返回類型是 IEnumerator ,並且在使用foreach時 in 后面直接是類名。而自定義迭代器 GetChildren 的返回類型是 IEnumerable,並且在使用foreach時 in 后面是 PeopleEnum.GetChildren(類名.迭代器名)。好像,好像是規定這樣子的,原理是什么還不清楚。

 


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM