这篇随笔是对上一篇随笔C#关键字:yield的扩展。

关于foreach

首先,对于 foreach ,大家应该都非常熟悉,这里就简单的描述下。

foreach 语句用于对实现  System.Collections.IEnumerable  或 System.Collections.Generic.IEnumerable<T> 接口的数组或对象集合中的每个元素进行循环访问,但不能用于在源集合中添加或移除项,否则可能产生不可预知的副作用。如果需要在源集合中添加或移除项,应使用 for  循环。

foreach的原理

foreach语句是被设计用来和可枚举类型一起使用,只要它的遍历对象是可枚举类型(实现了IEnumerable),比如数组。调用过程如下:

  1. 调用GetEnumerator()方法,返回一个IEnumerator引用。
  2. 调用返回的IEnumerator接口的MoveNext()方法。
  3. 如果MoveNext()方法返回true,就使用IEnumerator接口的Current属性获取对象的一个引用,用于foreach循环。
  4. 重复前面两步,直到MoveNext()方法返回false为止,此时循环停止。

我们可以通过代码模拟foreach的执行过程,如下:

static void Main()
{
int[] arr = { , , , , }; // 声明并初始化数组。
IEnumerator ie = arr.GetEnumerator(); // 调用可枚举类型的GetEnumerator方法获得枚举数对象。
while (ie.MoveNext()) // 调用IEnumerator接口的MoveNext方法移到下一项。实现遍历数组。
{
int i = (int)ie.Current; // 调用IEnumerator接口的Current方法获取当前项。注意它返回的是object类型,需要强制转换类型。
Console.Write("{0} ", i);
}
// Output: 1 2 3 4 5
Console.ReadKey();
}

当然,如果使用foreach的话,就非常简单了,如下:

static void Main()
{
int[] arr = { , , , , };
foreach (int item in arr)
{
Console.Write("{0} ", item);
}
// Output: 1 2 3 4 5
Console.ReadKey();
}

接下来,再看一个复杂点的实例,如下:

class Program
{
static void Main()
{
// Create a Tokens instance.
Tokens f = new Tokens("This is a sample sentence.", new char[] { ' ', '-' }); // Display the tokens.
foreach (string item in f)
{
System.Console.WriteLine(item);
}
// Output:
// This
// is
// a
// sample
// sentence. Console.ReadKey();
}
} public class Tokens : IEnumerable
{
private string[] elements; public Tokens(string source, char[] delimiters)
{
// The constructor parses the string argument into tokens.
elements = source.Split(delimiters);
} // The IEnumerable interface requires implementation of method GetEnumerator.
public IEnumerator GetEnumerator()
{
return new TokenEnumerator(this);
} // Declare an inner class that implements the IEnumerator interface.
private class TokenEnumerator : IEnumerator
{
private int position = -;
private Tokens t; public TokenEnumerator(Tokens t)
{
this.t = t;
} // The IEnumerator interface requires a MoveNext method.
public bool MoveNext()
{
if (position < t.elements.Length - )
{
position++;
return true;
}
else
{
return false;
}
} // The IEnumerator interface requires a Reset method.
public void Reset()
{
position = -;
} // The IEnumerator interface requires a Current method.
public object Current
{
get
{
return t.elements[position];
}
}
}
}

参考文档

  1. C#中foreach的原来
  2. http://www.cnblogs.com/mcgrady/archive/2011/11/12/2246867.html
  3. https://msdn.microsoft.com/zh-cn/library/9yb8xew9%28v=vs.110%29.aspx

C#学习笔记:foreach原理的更多相关文章

  1. AlloyTouch.js 源码 学习笔记及原理说明

    alloyTouch这个库其实可以做很多事的, 比较抽象, 需要我们用户好好的思考作者提供的实例属性和一些回调方法(touchStart, change, touchMove, pressMove, ...

  2. AlloyFinger.js 源码 学习笔记及原理说明

    此手势库利用了手机端touchstart, touchmove, touchend, touchcancel原生事件模拟出了 rotate  touchStart  multipointStart   ...

  3. lazy-load-img.js 源码 学习笔记及原理说明

    lazy-load-img.js? 1. 什么鬼? 一个轻量级的图片懒加载,我个人很是喜欢. 2. 有什么优势? 1.原生js开发,不依赖任何框架或库 2.支持将各种宽高不一致的图片,自动剪切成默认图 ...

  4. BiLSTM-CRF学习笔记(原理和理解) 维特比

    BiLSTM-CRF 被提出用于NER或者词性标注,效果比单纯的CRF或者lstm或者bilstm效果都要好. 根据pytorch官方指南(https://pytorch.org/tutorials/ ...

  5. JeeSite学习笔记~代码生成原理

    1.建立数据模型[单表,一对多表,树状结构表] 用ERMaster建立数据模型,并设定对应表,建立关联关系 2.系统获取对应表原理 1.怎样获取数据库的表 genTableForm.jsp: < ...

  6. 学习笔记7_Java_day11_JSP原理(5)

    4. jsp原理(理解) * jsp其实是一种特殊的Servlet > 当jsp页面第一次被访问时,服务器会把jsp编译成java文件(这个java其实是一个servlet类) > 然后再 ...

  7. Git学习笔记1--Git原理简单介绍

    Git是一个分布式的版本号控制工具,假设想用github等版本号控制系统,核心就是git,以下简介一些git的基础原理,原文:http://git-scm.com/book/en/Getting-St ...

  8. php学习笔记-foreach循环

    顾名思义,foreach是for each的连写,不是for reach.意思就是对数组中的每个元素都要处理一次. foreach只能用来处理数组. 有两种用法,先看第一种. foreach(arra ...

  9. 深度学习笔记——PCA原理与数学推倒详解

    PCA目的:这里举个例子,如果假设我有m个点,{x(1),...,x(m)},那么我要将它们存在我的内存中,或者要对着m个点进行一次机器学习,但是这m个点的维度太大了,如果要进行机器学习的话参数太多, ...

  10. mysql学习笔记-底层原理详解

    前言 我相信每一个程序员都避免不了和数据库打交道,其中Mysql以其轻量.开源成为当下最流行的关系型数据库.Mysql5.0以前以MyISAM作为默认存储引擎,在5.5版本以后,以InnoDB作为默认 ...

随机推荐

  1. ZJOI2012题解

    t1灾难 给一个食物网 如果一个生物吃的所有东西都灭绝了 它也跟着灭绝 求每个生物灭绝时跟着灭绝的生物数量 支配树裸题,我们先拓扑排序,然后建立一棵树满足一个点灭绝时,有且仅有它的子树跟着灭绝 考虑如 ...

  2. pytorch------cpu与gpu load时相互转化 torch.load(map_location=)

    将gpu改为cpu时,遇到一个报错: RuntimeError: Attempting to deserialize object on a CUDA device but torch.cuda.is ...

  3. ScikitLearn 学习器类型

    源自在线课程的学习:http://www.studyai.com/course/detail/d086826e9be84b818f9c54893633663d

  4. session.write类型引发的思考---Mina Session.write流程探索.doc--zhengli

    基于Mina开发网络通信程序,在传感器数据接入领域应用的很广泛,今天我无意中发现一个问题,那就是我在前端session.write(msg)数据出去之后,却没有经过Filter的Encoder方法,同 ...

  5. UDK游戏打包详解

    转自:http://blog.sina.com.cn/s/blog_944177030100ycki.html 安装完的udk目录下有4个主要的文件夹 Binaries -这个文件夹包含游戏的exe程 ...

  6. [poj2342]Anniversary party树形dp入门

    题意:选出不含直接上下司关系的最大价值. 解题关键:树形dp入门题,注意怎么找出根节点,运用了并查集的思想. 转移方程:dp[i][1]+=dp[j][0];/i是j的子树 dp[i][0]+=max ...

  7. Linux运行Tomcat下的war文件

    1.查看Tomcat进程: ps -ef |grep tomcat 2.关闭Tomcat进程: kill -9 pid 3.关闭Tomcat运行: bin目录下执行 ./shutdown.sh 4. ...

  8. DOM,API,CSS,href,万方db文章,数据库工程师要求

    DOM,文档对象模型(Document Object Model),是W3C组织推荐的处理可扩展标志语言的标准编程接口. API,应用程序接口 (API:Application Program Int ...

  9. ios之Block研究

    Block的好处,我总结了下主要有2点:1.用于回调特别方便,2.可以延长对象的作用区域.但是,Block的内存管理这个模块一直不是很清楚,这个周末好好的看了下Block的原理,有些许心得. 为了性能 ...

  10. loj #6079. 「2017 山东一轮集训 Day7」养猫【最大费用最大流】

    首先假设全睡觉,然后用费用流考虑平衡要求建立网络流 把1~n的点看作是i-k+1~k这一段的和,连接(i,i+k,1,e[i]-s[i]),表示把i改成吃饭,能对i~i+k-1这一段的点产生影响:然后 ...