我们知道数组对象可以使用foreach迭代进行遍历,同时我们发现类ArrayList和List也可以使用foreach进行迭代。如果我们自己编写的类也需要使用foreach进行迭代时该怎么办呢?

IEnumerable:

 public interface IEnumerable
{
IEnumerator GetEnumerator();
}

如果自己编写的类需要foreach进行迭代就需要实现IEnumerable接口,表示当前的类可以进行迭代。

我们发现该接口唯一的方法返回的是另一个接口IEnumerator,下面看看这个接口是干嘛的。

IEnumerator:

 public interface IEnumerator
{
object Current { get; }
bool MoveNext();
void Reset();
}

如果说IEnumerable接口是表示当前类可以进行迭代,那么IEnumerator则是实现迭代逻辑的接口,我们需要编写一个实现IEnumerator接口的类并在其中编写好迭代逻辑。

下面直接上一个例子:

People.cs:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Test
{
/// <summary>
/// 自定义的可迭代类.
/// </summary>
class People : IEnumerable<Person>
{
//这里用了一个 List 有点无聊, 因为 List 本身就可以进行迭代, 为了写例子没办法
private List<Person> _list; public People()
{
_list = new List<Person>();
} public IEnumerator<Person> GetEnumerator()
{
return new PeopleEnumerator(_list.ToArray());
} //示例程序所以这里就添加一个方法就行了
public void AddPerson(Person person)
{
_list.Add(person);
} System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
} /// <summary>
/// 迭代器的逻辑实现类.
/// </summary>
class PeopleEnumerator : IEnumerator<Person>
{
public Person[] pers; private int index = -; public PeopleEnumerator(Person[] pers)
{
this.pers = pers;
} public Person Current
{
get
{
return pers[index];
}
} public bool MoveNext()
{
index++;
return index < pers.Length;
} public void Reset()
{
index = -;
} public void Dispose()
{
pers = null;
} object System.Collections.IEnumerator.Current
{
get { return Current; }
}
} /// <summary>
/// 集合的元素.
/// </summary>
class Person
{
public string name;
public bool isMale; public Person(string name, bool isMale)
{
this.name = name;
this.isMale = isMale;
}
}
}

Program.cs:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Test
{
class Program
{
static void Main(string[] args)
{
new Program(); Console.ReadKey();
} public Program()
{
People people = new People();
people.AddPerson(new Person("tony", true));
people.AddPerson(new Person("tony mom", false));
people.AddPerson(new Person("alen", true));
people.AddPerson(new Person("gilbret", true));
people.AddPerson(new Person("mark", false)); foreach(Person person in people)
{
Console.WriteLine("Name: {0}, sex is male:{1}", person.name, person.isMale);
}
}
}
}

下面是运行结果:

 Name: tony, sex is male:True
Name: tony mom, sex is male:False
Name: alen, sex is male:True
Name: gilbret, sex is male:True
Name: mark, sex is male:False

yield:

yield 是 C# 提供的一个特殊的用于迭代的语法,其可以简化迭代实现的代码,yield return 语句返回集合的一个元素,并移动到下一个元素上,yield break 可以停止迭代。

头晕了吧?没关系,我们先看看一个简单的例子:

 using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Test
{
class Program
{
static void Main(string[] args)
{
new Program(); Console.ReadKey();
} public Program()
{
People people = new People(); foreach(string name in people)
{
Console.WriteLine(name);
}
}
} class People : IEnumerable
{
public IEnumerator GetEnumerator()
{
yield return "gilbert";
yield return "alen";
yield return "grace";
}
}
}

运行的结果为:

 gilbert
alen
grace

没错,当程序碰到yield return这个语句时就将其后面附带的数据作为current返回,同时程序会再此处暂停,运行结束foreach中的代码后再继续,同时执行的是下一个语句了,我们再看看yield break的效果,该效果表示立即停止迭代,示例如下:

 using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Test
{
class Program
{
static void Main(string[] args)
{
new Program(); Console.ReadKey();
} public Program()
{
People people = new People(); foreach(string name in people)
{
Console.WriteLine(name);
}
}
} class People : IEnumerable
{
public IEnumerator GetEnumerator()
{
yield return "gilbert";
yield return "alen";
yield break;//指示这里要停止迭代
yield return "grace";
}
}
}

运行的结果为:

 gilbert
alen

最后要说一下:包含yoeld语句的方法或者属性也称为迭代块,迭代块必须声明为返回IEnumerator或IEnumerable接口,迭代块可以包含多个yield return或yield break语句,但是不能包含return语句。

不要小看yield迭代快,下一篇笔记我要可转回U3D了,我们要详细的看看yield在U3D里的变种——协程。

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

  1. ICollection IEnumerable/IEnumerator IDictionaryEnumerator yield

    Enumerable和IEnumerator接口是.NET中非常重要的接口,二者区别: 1. IEnumerable是个声明式的接口,声明实现该接口的类就是“可迭代的enumerable”,但并没用说 ...

  2. C# ~ 从 IEnumerable / IEnumerator 到 IEnumerable<T> / IEnumerator<T> 到 yield

    IEnumerable / IEnumerator 首先,IEnumerable / IEnumerator 接口定义如下: public interface IEnumerable /// 可枚举接 ...

  3. IEnumerable, IEnumerator接口

    IEnumerable接口 // Exposes the enumerator, which supports a simple iteration over a non-generic collec ...

  4. [原译]实现IEnumerable接口&理解yield关键字

    原文:[原译]实现IEnumerable接口&理解yield关键字 著作权声明:本文由http://leaver.me 翻译,欢迎转载分享.请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢 ...

  5. [Python 学习]2.5版yield之学习心得 - limodou的学习记录 - limodou是一个程序员,他关心的焦点是Python, DocBook, Open Source …

    [Python 学习]2.5版yield之学习心得 - limodou的学习记录 - limodou是一个程序员,他关心的焦点是Python, DocBook, Open Source - [Pyth ...

  6. c#yield,IEnumerable,IEnumerator

    foreach 在编译成IL后,实际代码如下: 即:foreach实际上是先调用可枚举对象的GetEnumerator方法,得到一个Enumerator对象,然后对Enumerator进行while循 ...

  7. 【Unity|C#】基础篇(20)——枚举器与迭代器(IEnumerable/IEnumerator)

    [学习资料] <C#图解教程>(第18章):https://www.cnblogs.com/moonache/p/7687551.html 电子书下载:https://pan.baidu. ...

  8. 转-[Python 学习]2.5版yield之学习心得

    在 shhgs 发布了关于< Py 2.5 what’s new 之 yield>之后,原来我不是特别关注 yield 的用法,因为对于2.3中加入的yield相对来说功能简单,它是作为一 ...

  9. IEnumerable & IEnumerator

    IEnumerable 只有一个方法:IEnumerator GetEnumerator(). INumerable 是集合应该实现的一个接口,这样,就能用 foreach 来遍历这个集合. IEnu ...

随机推荐

  1. 初始化windows窗口

    LRESULT WINAPI WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) { PAINTSTRUCT ps; switch (msg ...

  2. Android ActionBar通过Tab进行不同的Fragment之间的交换

    ActionBar的使用常见于4.0系统,其Tab的使用挺广泛的. 在ActionBar中添加标签(Tabs),每个标签对应的是一个Fragment,点击不同的Tab时,就会切换到对应的Fragmen ...

  3. IIS7 发布mvc3.0

    Windows7系统和我们见面已经有一段时间了,在我们经过一段时间熟悉了她的新鲜好玩儿的功能之后,也许我们该静下心来想一下怎么用她做一些与学习有 关的事情,从Windows7的第一个试用版到现在的零售 ...

  4. Hadoop伪分布模式配置部署

    .实验环境说明 注意:本实验需要按照上一节单机模式部署后继续进行操作 1. 环境登录 无需密码自动登录,系统用户名 shiyanlou,密码 shiyanlou 2. 环境介绍 本实验环境采用带桌面的 ...

  5. UNIX 网络编程第五章读书笔记

    刚看完 UNIX 第五章内容,我想按照自己的方式将自己获得的知识梳理一遍,以便日后查看!先贴上一段简单的 TCP 服务器端代码: #include <sys/socket.h> #incl ...

  6. poj 1836 Alignment(dp)

    题目:http://poj.org/problem?id=1836 题意:最长上升子序列问题, 站队,求踢出最少的人数后,使得队列里的人都能看到 左边的无穷远处 或者 右边的无穷远处. 代码O(n^2 ...

  7. poj1226,poj3080

    看来以后用pascal的函数要小心了: 简简单单pos其实时间复杂度是二次方级的…… 今天学习的是KMP——字符匹配算法: 这两道题也都很简单,都是为这个算法练手的, 最朴素的匹配显然是穷举起始位置然 ...

  8. android LayoutInflater和inflate()方法的用法(转载)

    原文出处:http://www.cnblogs.com/top5/archive/2012/05/04/2482328.html 在实际开发中LayoutInflater这个类还是非常有用的,它的作用 ...

  9. ExecuteStoreQuery

    using (var webdb = new kyj_NewHouseDBEntities()) { string sql = "select * from developer where ...

  10. 用纯css写出三角形

    1.新建一个元素,随便什么元素,不过我习惯性的会用块元素来做.如果行内元素就display:block它.<div class="triangle"></div& ...