我们知道数组对象可以使用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. java synchronized wait

    在多个线程要互斥访问数据,但线程间需要同步时——例如任务分多个阶段,特定线程负责特定阶段的情况,经常合作使用synchronized 和 wait() /** * * 计算输出其他线程锁计算的数据 * ...

  2. php修改排序,上移下移

    php修改排序,上移下移 /**    $UpDown //移动方向,up或down    $table //表名    $id //当前移动的ID    $id_col //ID字段的名称    $ ...

  3. 23.allegro中钻孔[原创]

    1.钻孔: NC Parameters,NC Drill, Dill Legend, NC Route ----------------------- ------ ----- ------- --- ...

  4. Android开发之AIDL的使用一--跨应用启动Service

    启动其他App的服务,跨进程启动服务. 与启动本应用的Service一样,使用startService(intent)方法 不同的是intent需要携带的内容不同,需要使用intent的setComp ...

  5. Android反编译教程

    本文摘自 http://blog.csdn.net/ithomer/article/details/6727581 本文Android反编译教程,测试环境: Win7 Ultimate x64 Ubu ...

  6. android 三目运算符 运用错误

    /************************************************************************** * android 三目运算符 运用错误 * 说 ...

  7. 如何在CentOS 5.x 中安装Windows Azure Linux Agent (WALA)

    Qing Liu  Tue, Mar 10 2015 3:06 AM 在今天的这一个章节中,我们主要讨论在CentOs 5.x 中如何安装Windows Azure Linux Agent 2.11 ...

  8. window.location.search作用

    window.location.search.substr(1).split("&") 这里面的相关属性和时间还有参数能具体说明一下吗?window.location wi ...

  9. http://www.cnblogs.com/youfan/articles/3216816.html

    我对 CodeFirst 的理解,与之对应的有 ModelFirst与 DatabaseFirst ,三者各有千秋,依项目实际情况自行选择. 1.开发过程中先行设计数据库并依此在项目中生成 *.dbm ...

  10. Key/Value之王Memcached初探:二、Memcached在.Net中的基本操作 - Edison Chou

    一.Memcached ClientLib For .Net 首先,不得不说,许多语言都实现了连接Memcached的客户端,其中以Perl.PHP为主. 仅仅memcached网站上列出的语言就有: ...