IEnumerable、IEnumerator与yield的学习

时间:2022-09-11 10:01:42

我们知道数组对象可以使用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&sol;IEnumerator IDictionaryEnumerator yield

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

  2. C&num; ~ 从 IEnumerable &sol; IEnumerator 到 IEnumerable&lt&semi;T&gt&semi; &sol; IEnumerator&lt&semi;T&gt&semi; 到 yield

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

  3. IEnumerable&comma; IEnumerator接口

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

  4. &lbrack;原译&rsqb;实现IEnumerable接口&amp&semi;理解yield关键字

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

  5. &lbrack;Python 学习&rsqb;2&period;5版yield之学习心得 - limodou的学习记录 - limodou是一个程序员,他关心的焦点是Python&comma; DocBook&comma; Open Source …

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

  6. c&num;yield&comma;IEnumerable&comma;IEnumerator

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

  7. 【Unity&vert;C&num;】基础篇&lpar;20&rpar;——枚举器与迭代器(IEnumerable&sol;IEnumerator)

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

  8. 转-&lbrack;Python 学习&rsqb;2&period;5版yield之学习心得

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

  9. IEnumerable &amp&semi; IEnumerator

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

随机推荐

  1. Spring 整合 Redis

    http://blog.csdn.net/java2000_wl/article/details/8543203/ pom构建: <modelVersion>4.0.0</model ...

  2. Swift函数编程之Map、Filter、Reduce

    在Swift语言中使用Map.Filter.Reduce对Array.Dictionary等集合类型(collection type)进行操作可能对一部分人来说还不是那么的习惯.对于没有接触过函数式编 ...

  3. mybatis配置文件(其中,注意节点先后顺序)

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC & ...

  4. Winform 基础知识 之文件夹操作

    using System.IO; /// <summary> /// 删除文件夹下所有文件 /// </summary> /// <param name="di ...

  5. ASP&period;NET - 获得客户端的 IP 地址

    通常我们都通过下面的代码获得IP: REMOTE_ADDR 说明:访问客户端的 IP 地址. 此项信息用户不可以修改.如果真的给改了的话,你也和服务器连接不了了,服务器就是按照这个来与客户端建立连接并 ...

  6. chapter11&lowbar;2 Lua链表与队列

    链表 由于table是动态的实体,所以在Lua中实现链表是很方便的.每个节点以一个table来表示,一个“链表”只是节点table中的一个字段. 该字段包含了对其他table的引用.例如,要实现一个基 ...

  7. Advanced Sort Algorithms

    1. Merge Sort public class Mergesort { private int[] numbers; private int[] helper; private int numb ...

  8. 转载 Flask中客户端 - 服务器 - web应用程序 是如何处理request生成response的&quest;

    文章转载自https://blog.csdn.net/weixin_37923128/article/details/80992645 , 感谢原作者 当客户端向服务器发送一个请求时,服务器会将请求转 ...

  9. 用tkinter制作签名设计窗口

    效果如下: from tkinter import * from tkinter import messagebox import requests import re from PIL import ...

  10. 弹性盒子 flexbox 元素居中

    1 .navtext{ width:800px; height:600px; border: 1px solid black; justify-content:center; align-items: ...