原文:对[foreach]的浅究到发现[yield]

  闲来无事,翻了翻以前的代码,做点总结,菜鸟从这里起航,呵呵。

一、List的foreach遍历

  先上代码段[1]:

  class Program
{
static void Main(string[] args)
{
List<string> dayList = new List<string> { "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" };
foreach (var day in dayList)
{
Console.WriteLine(day);
}
Console.ReadKey();
}
}

  这是我们经常用的,简单明了,这里就不赘述了。

二、对List的浅究

  接着我就产生了疑问,List具有怎样的特性才使得foreach可以对它进行遍历呢?这个遍历是如何实现的?

  下面就来浅究,再上代码段[2]:

     public class DaysList<T> : System.Collections.IEnumerable
{
T[] daysArry;
public DaysList(T[] days)
{
daysArry = days;
}
public System.Collections.IEnumerator GetEnumerator()
{
for (int i = ; i < daysArry.Length; i++)
{
yield return daysArry[i];
}
}
} class Program
{
static void Main(string[] args)
{
string[] days = { "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" };
var daysList = new DaysList<string>(days); foreach (string day in daysList)
{
System.Console.WriteLine(day);
}
Console.ReadKey();
}
}

  通过查阅我们发现LIst是通过实现System.Collections.IEnumerable接口来达到可以被遍历的能力,而实现System.Collections.IEnumerable接口必须实现它里面的GetEnumerator()方法,用来返回一个循环访问集合的枚举器,代码段[2]中就有我对GetEnumerator()方法的实现,其中有个关键字[yield]不知大家注意到没。

  我的理解是:与其说是foreach遍历List,不如说是foreach遍历的是List中的GetEnumerator()方法返回的枚举器,注意这个枚举器实现了IEnumerator 接口,(插句话,IEnumerable接口标识某个类具备被遍历的能力,而IEnumerator 接口则使某个类真正具备这个能力!)。而当foreach对List进行循环遍历时,每个循环就是通过[yield]来分隔的。

三、对foreach的浅究

  通过标题二,我们大概对List进行了了解,但不清楚,下面看看foreach。

  依旧代码段[3]:

     //注意:其中类DaysList<T>的实现同代码段[2]一样
//这里只展示foreach的实现。
class Program
{
static void Main(string[] args)
{
string[] days = { "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat" };
var daysList = new DaysList<string>(days); System.Collections.IEnumerator enumertor = daysList.GetEnumerator();
while (enumertor.MoveNext())
{
System.Console.WriteLine(enumertor.Current);
}
Console.ReadLine();
}
}

  就像上面说的,foreach其实遍历的是List中的GetEnumerator()方法返回的枚举器enumertor,而这个枚举器所实现的接口IEnumerator中定义了只读的Current属性(用来获取枚举器当前的所指的集合中的元素)、MoveNext方法(将枚举器推进到集合中的下一个元素,返回值代表是否到了集合末尾)、Reset方法(使枚举器指到集合第一个元素之前,也就是重置枚举器),明白了这些,我们就可以像代码段[3]中一样通过[while]语法来实现跟foreach一样的功能了,而上文中的[yield]关键字浅显的理解就是用来划分要遍历的集合中的每个元素的。

  最后,本来还想分析分析这个实现了IEnumerator接口的枚举器是怎么生成的,想象一下它的内部实现,应该很有意思!

  就这样吧,下班了,大家共勉!

对[foreach]的浅究到发现[yield]的更多相关文章

  1. 对[yield]的浅究到发现[async][await]

    原文:对[yield]的浅究到发现[async][await] 上篇对[foreach]的浅究到发现[yield]写完后,觉得对[yield]还没有理解清楚,想起曾经看过一位大牛的帖子讲的很深刻(链接 ...

  2. 【Python学习笔记之二】浅谈Python的yield用法

    在上篇[Python学习笔记之一]Python关键字及其总结中我提到了yield,本篇文章我将会重点说明yield的用法 在介绍yield前有必要先说明下Python中的迭代器(iterator)和生 ...

  3. 字典查找、linq、foreach、yield等几种查找性能对比

    先上代码,以1千万记录的内存查找测试: List<Student> stuList = new List<Student>(); Dictionary<int, Stud ...

  4. C# 中yield关键字解析

    前言 前段时间了解到yield关键字,一直觉得还不错.今天给大家分享一下yield关键字的用法.yield return 返回集合不是一次性返回所有集合元素,而是一次调用返回一个元素.具体如何使用yi ...

  5. C# yield return 原理探究

    天需要些一个小工具,需要使用到多线程读写程序集,接口方法返回值类型需要为"IEnumerable<string>"这里用到了"yield return&quo ...

  6. Python 生成器与迭代器 yield 案例分析

    前几天刚开始看 Python ,后因为项目突然到来,导致Python的学习搁置了几天.然后今天看回Python 发现 Yield 这个忽然想不起是干嘛用的了(所以,好记性不如烂笔头.).然后只能 花点 ...

  7. 浅谈inline-block

    一.区分block,inline,inline-block 1.block block元素会独占一行,多个block元素会各自新起一行.默认情况下,block元素宽度自动填满其父元素宽度. block ...

  8. forEach循环对集合进行循环时,需判断是否为null;

    分析forEach的源码会发现:foreach源码例子: public class Foreach { public static void main(String[] args) { List< ...

  9. List<T>.ForEach 调用异步方法的意外

    有这么个异步方法 private static async Task<int> Compute(int s) { return await Task<int>.Run(() = ...

随机推荐

  1. zend studio 安装emmet(zen coding)

    help->Install New Software 在work with后面点击Add,弹出的对话框中填写信息: Name:随意 Location:http://emmet.io/eclips ...

  2. 最小二乘法拟合java实现源程序(转)

    因为我所在的项目要用到最小二乘法拟合,所有我抽时间将C++实现的程序改为JAVA实现,现在贴出来,供大家参考使用./** * <p>函数功能:最小二乘法曲线拟合</p> * @ ...

  3. Bulk Insert具体订单

    Bulk Insert具体订单 BULK INSERT与用户指定的格式的数据文件复制到数据库表或视图. 语法: BULK INSERT [ [ 'database_name'.][ 'owner' ] ...

  4. MVC—WebAPI(调用、授权)

    ASP.NET MVC—WebAPI(调用.授权)   本系列目录:ASP.NET MVC4入门到精通系列目录汇总 微软有了Webservice和WCF,为什么还要有WebAPI? 用过WCF的人应该 ...

  5. 第一pga 畸形消费分析

     第一pga 畸形消费分析 os: aix 6 db:10205 ------使用os 命令观察oracle 存消耗情况 #ps gv ......                         ...

  6. JSP_include指令和&lt;jsp:include&gt;

    包括三个文件:jsp_include.jsp, static.html, two.jsp 周边环境:tomcat7.0. myeclipse10 1.jsp_include.jsp <%@ pa ...

  7. Visual Studio Team Services使用教程--添加团队成员

  8. MEF初体验之五:Lazy Exports

    在一个部件组合中,导入将触发一个部件或者多个部件的实例化,这些部件暴露了所需原请求部件的必要的导入.对于一些应用程序来说,延迟实例化-防止图结构下的递归组合-可能对于将创建一个长久复杂的开销很大而不必 ...

  9. Struts1项目转成Struts2项目步奏

    注意:要转成Struts2必须struts2配置和流程理解,我不知道,我只能说还是知道struts2然后转成struts2对. 1.先备份一份.不要没转成功项目搞蹦了都回不来了. 2.导入Struts ...

  10. IOS 数据库管理系统(SQLite)

    嵌入式数据库 SQLite嵌入式数据库的优势 1.支持事件,你并不需要配置,无需安装,不需要管理员 2.支持部分脂肪SQL92 3.完整的数据库被存储在磁盘上的文件的顶部,相同的数据库文件可以在不同机 ...