这篇随笔是对上一篇随笔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. Mac替换sublime图标

    下载.icns格式一个图标:http://www.easyicon.net/language.en/iconsearch/sublime/ 终端执行:open /Applications/Sublim ...

  2. Codeforces Gym 101190 NEERC 16 .D Delight for a Cat (上下界的费用流)

    ls是一个特别堕落的小朋友,对于n个连续的小时,他将要么睡觉要么打隔膜,一个小时内他不能既睡觉也打隔膜 ,因此一个小时内他只能选择睡觉或者打隔膜,当然他也必须选择睡觉或打隔膜,对于每一个小时,他选择睡 ...

  3. poj2411铺砖——状压DP

    题目:http://poj.org/problem?id=2411 状态压缩,一行的状态记为一个二进制数,从上往下逐行DP,答案输出最后一行填0的方案数. 代码如下: #include<iost ...

  4. 最短路径 一 Dijkstra 模板(O(n^2))

    题目传送:http://hihocoder.com/problemset/problem/1081 #include<iostream> #include<cstdio> #i ...

  5. cassandra迁移表数据

    cassandra的迁移表数据有2种方式,以keyspace名为mydb,table名为user为例子: 方法一:copy命令. 这种方式适合数据量较小的情况. 1.进入cqlsh,输入命令:COPY ...

  6. JMETER 定时器 之 常数吞吐量定时器

    定时器: 默认情况下,Jmeter线程在发送请求之间没有间歇.建议为线程组添加某种定时器,以便设定请求之间应该隔多长时间.如果测试人员不设定这种延迟,Jmeter可能会在短时间内产生大量访问请求,导致 ...

  7. 【249】◀▶IEW-Unit14

    Unit 14 Money and Finance 线图写作技巧 1.Model1对应图片分析 The graph contains information about the price in US ...

  8. Linux命令总结_查看主机磁盘使用

    1.dh -h 查看各个挂载点的使用量 2.du -sh *(星号表示当前所有文件夹)可以查看当前目录下各个文件夹的大小,-s表示只显示当前文件夹(不加-s你可以看到所有文件夹下的子文件夹的大小,太多 ...

  9. fkmu

    杭州赛区J:考虑实质上是求解 (a,b) = 1 且 a*b<=n的数对个数,枚举a,对b容斥. trickgcd:考虑反向求解,即为ans[x] -= ans[t*x],注意到因为反向求所以余 ...

  10. hadoop学习笔记之-hbase完全分布模…

    安装环境: OS: Oracle linux 5.6 JDK: jdk1.6.0_18 Hadoop: hadoop-0.20.2 Hbase: hbase-0.90.5 安装准备: 1. Jdk环境 ...