我们知道数组对象可以使用foreach迭代进行遍历,同时我们发现类ArrayList和List也可以使用foreach进行迭代。如果我们自己编写的类也需要使用foreach进行迭代时该怎么办呢?
IEnumerable:
1 public interface IEnumerable
2 {
3 IEnumerator GetEnumerator();
4 }
如果自己编写的类需要foreach进行迭代就需要实现IEnumerable接口,表示当前的类可以进行迭代。
我们发现该接口唯一的方法返回的是另一个接口IEnumerator,下面看看这个接口是干嘛的。
IEnumerator:
1 public interface IEnumerator
2 {
3 object Current { get; }
4 bool MoveNext();
5 void Reset();
6 }
如果说IEnumerable接口是表示当前类可以进行迭代,那么IEnumerator则是实现迭代逻辑的接口,我们需要编写一个实现IEnumerator接口的类并在其中编写好迭代逻辑。
下面直接上一个例子:
People.cs:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace Test
8 {
9 /// <summary>
10 /// 自定义的可迭代类.
11 /// </summary>
12 class People : IEnumerable<Person>
13 {
14 //这里用了一个 List 有点无聊, 因为 List 本身就可以进行迭代, 为了写例子没办法
15 private List<Person> _list;
16
17 public People()
18 {
19 _list = new List<Person>();
20 }
21
22 public IEnumerator<Person> GetEnumerator()
23 {
24 return new PeopleEnumerator(_list.ToArray());
25 }
26
27 //示例程序所以这里就添加一个方法就行了
28 public void AddPerson(Person person)
29 {
30 _list.Add(person);
31 }
32
33 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
34 {
35 return this.GetEnumerator();
36 }
37 }
38
39 /// <summary>
40 /// 迭代器的逻辑实现类.
41 /// </summary>
42 class PeopleEnumerator : IEnumerator<Person>
43 {
44 public Person[] pers;
45
46 private int index = -1;
47
48 public PeopleEnumerator(Person[] pers)
49 {
50 this.pers = pers;
51 }
52
53 public Person Current
54 {
55 get
56 {
57 return pers[index];
58 }
59 }
60
61 public bool MoveNext()
62 {
63 index++;
64 return index < pers.Length;
65 }
66
67 public void Reset()
68 {
69 index = -1;
70 }
71
72 public void Dispose()
73 {
74 pers = null;
75 }
76
77 object System.Collections.IEnumerator.Current
78 {
79 get { return Current; }
80 }
81 }
82
83 /// <summary>
84 /// 集合的元素.
85 /// </summary>
86 class Person
87 {
88 public string name;
89 public bool isMale;
90
91 public Person(string name, bool isMale)
92 {
93 this.name = name;
94 this.isMale = isMale;
95 }
96 }
97 }
Program.cs:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading.Tasks;
6
7 namespace Test
8 {
9 class Program
10 {
11 static void Main(string[] args)
12 {
13 new Program();
14
15 Console.ReadKey();
16 }
17
18 public Program()
19 {
20 People people = new People();
21 people.AddPerson(new Person("tony", true));
22 people.AddPerson(new Person("tony mom", false));
23 people.AddPerson(new Person("alen", true));
24 people.AddPerson(new Person("gilbret", true));
25 people.AddPerson(new Person("mark", false));
26
27 foreach(Person person in people)
28 {
29 Console.WriteLine("Name: {0}, sex is male:{1}", person.name, person.isMale);
30 }
31 }
32 }
33 }
下面是运行结果:
1 Name: tony, sex is male:True 2 Name: tony mom, sex is male:False 3 Name: alen, sex is male:True 4 Name: gilbret, sex is male:True 5 Name: mark, sex is male:False
yield:
yield 是 C# 提供的一个特殊的用于迭代的语法,其可以简化迭代实现的代码,yield return 语句返回集合的一个元素,并移动到下一个元素上,yield break 可以停止迭代。
头晕了吧?没关系,我们先看看一个简单的例子:
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6 using System.Threading.Tasks;
7
8 namespace Test
9 {
10 class Program
11 {
12 static void Main(string[] args)
13 {
14 new Program();
15
16 Console.ReadKey();
17 }
18
19 public Program()
20 {
21 People people = new People();
22
23 foreach(string name in people)
24 {
25 Console.WriteLine(name);
26 }
27 }
28 }
29
30 class People : IEnumerable
31 {
32 public IEnumerator GetEnumerator()
33 {
34 yield return "gilbert";
35 yield return "alen";
36 yield return "grace";
37 }
38 }
39 }
运行的结果为:
1 gilbert 2 alen 3 grace
没错,当程序碰到yield return这个语句时就将其后面附带的数据作为current返回,同时程序会再此处暂停,运行结束foreach中的代码后再继续,同时执行的是下一个语句了,我们再看看yield break的效果,该效果表示立即停止迭代,示例如下:
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6 using System.Threading.Tasks;
7
8 namespace Test
9 {
10 class Program
11 {
12 static void Main(string[] args)
13 {
14 new Program();
15
16 Console.ReadKey();
17 }
18
19 public Program()
20 {
21 People people = new People();
22
23 foreach(string name in people)
24 {
25 Console.WriteLine(name);
26 }
27 }
28 }
29
30 class People : IEnumerable
31 {
32 public IEnumerator GetEnumerator()
33 {
34 yield return "gilbert";
35 yield return "alen";
36 yield break;//指示这里要停止迭代
37 yield return "grace";
38 }
39 }
40 }
运行的结果为:
1 gilbert 2 alen
最后要说一下:包含yoeld语句的方法或者属性也称为迭代块,迭代块必须声明为返回IEnumerator或IEnumerable接口,迭代块可以包含多个yield return或yield break语句,但是不能包含return语句。
不要小看yield迭代快,下一篇笔记我要可转回U3D了,我们要详细的看看yield在U3D里的变种——协程。
来源:https://www.cnblogs.com/hammerc/p/4428191.html