IEnumerable、IEnumerator与yield的学习

我们知道数组对象可以使用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里的变种——协程

时间: 2024-10-10 15:11:22

IEnumerable、IEnumerator与yield的学习的相关文章

c#yield,IEnumerable,IEnumerator

foreach 在编译成IL后,实际代码如下: 即:foreach实际上是先调用可枚举对象的GetEnumerator方法,得到一个Enumerator对象,然后对Enumerator进行while循环的相关操作,然后得到可枚举对象中的每一个值. 可以把可枚举对象中的所有值想像成一个链表,Enumerator是链表的指针,Enumerator.Current是当前指向的元素,Enumerator.MoveNext是指针后移.于是用while循环便可以用类似遍历链表的方式得到对象中的所有值. 一个

C#基础复习IEnumerable(和 yield return的使用滴呀 )

IEnumerable 真是基础中的基础,然而..... 我们直接来看看这个接口的实现吧: 它是一个公开枚举数,该枚举数支持在非泛型集合上进行简单的迭代.换句话说,对于所有数组的遍历,都来自IEnumerable,那么我们就可以利用这个特性,来定义一个能够遍历xxxxxx的通用方法 先看我们的经典实例1: using System; using System.Collections; using System.Collections.Generic; using System.Linq; usi

IEnumerable &amp; IEnumerator

IEnumerable 只有一个方法:IEnumerator GetEnumerator(). INumerable 是集合应该实现的一个接口,这样,就能用 foreach 来遍历这个集合. IEnumerator 有Current属性,MoveNext(), Reset()两个方法. 当 foreach 使用到一个 IEnumerable 的集合上的时候,遍历是这样开始的: 1. 调用 GetEnumerator() 得到一个 IEnumerator 的对象. 2. 调用 MoveNext()

C#学习笔记(六):可空类型、匿名方法和迭代器

可空类型 为啥要引入可空类型? 在数据库中,字段是可以为null值的,那么在C#中为了方便的操作数据库的值,微软引入了可空类型. 声明可空类型 我们可以使用两种方法声明一个可空类型: 1 Nullable<int> i = null; 2 int? i = null; 第二行是第一行的简写方法,其中“?”是微软为可空类型提供的一个语法糖. 我们看看可空类型的实现: 1 // Type: System.Nullable`1 2 // Assembly: mscorlib, Version=4.0

IEnumerator/ IEnumerable/ yield return/ StartCoroutine 详解

IEnumerator/ IEnumerable public interface IEnumerable { IEnumerator GetEnumerator(); } public interface IEnumerator { bool MoveNext(); void Reset(); Object Current { get; } } 在两者的使用上,有下面几点需要注意 1.一个Collection要支持foreach方式的遍历,必须实现IEnumerable接口(亦即,必须以某种方

C# 常用接口学习 IEnumerable&lt;T&gt;

C# 常用接口学习 IEnumerable<T> 作者:乌龙哈里 时间:2015-10-24平台:Window7 64bit,Visual Studio Community 2015 本文参考: MSDN IEnumerable<T> Interface MS DotNet 源代码 你曾实现过二叉树吗--匠心十年 你可能不知道的陷阱, IEnumerable接口--沙漠之鹰 本文章节: 正文: 本文是作者摸索学习.Net的过程,逐步进行,比较繁琐,是作者本人用来帮助记忆的博文. 我

IEnumerable和IEnumerator 详解

http://blog.csdn.net/byondocean/article/details/6871881 初学C#的时候,老是被IEnumerable.IEnumerator.ICollection等这样的接口弄的糊里糊涂,我觉得有必要切底的弄清楚IEnumerable和IEnumerator的本质. 下面我们先看IEnumerable和IEnumerator两个接口的语法定义.其实IEnumerable接口是非常的简单,只包含一个抽象的方法GetEnumerator(),它返回一个可用于

C# IEnumerable和IEnumerator的区别,如何实现

IEnumerable接口和IEnumerator接口是.NET中非常重要的接口,二者有何区别? 1. 简单来说IEnumerable是一个声明式的接口,声明实现该接口的类就是"可迭代的enumerable",但并没用说明如何实现迭代器(iterator).其代码实现为: public interface IEnumerable         {                IEnumerator GetEnumerator();          }    2. 而IEnumer

C# IEnumerator与 IEnumerable

1. 接口的使用 (1)  首先定义接口 public interface IBattleMapManager : { Stages CurrentStage { get; } event EventHandler<BeginFightEventArgs> EnterFight; } (2) 用定义实现类- 实现接口 public class BattleMapManager : IBattleMapManager, IDisposable { public Stages CurrentSta