这篇随笔是对上一篇随笔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. ACM学习历程——POJ 2376 Cleaning Shifts(贪心)

    Description Farmer John is assigning some of his N (1 <= N <= 25,000) cows to do some cleaning ...

  2. php之配置redis

    Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库. 配置说明:https://www.cnblogs.com/lucky-man/p/8359110.html ph ...

  3. jupyter-notebook重设项目工作路径

    一. . Anaconda Prompt 命令(方法没生效) 1 选择一个用于存放config文件的文件夹(先创建) 2 在cmd中进入该文件夹的路径 3在cmd中 输入​命令 jupyter not ...

  4. SHOI2001化工厂装箱员——记忆化搜索

    题目:https://www.luogu.org/problemnew/show/P2530 太弱了不会用DP,于是暴搜: 每次传进一个数组c记录当前状态各种物品有多少个,枚举取哪种物品,返回最小值, ...

  5. WPF Get Multibinding Expression, Update Source,

    wpf 拿到某个control的multibinding以及其中每个Binding 1. 拿到multibinding      MultiBindingExpression mbe = Bindin ...

  6. webAPP meta 标签大全

    1.先说说mate标签里的viewport: viewport即可视区域,对于桌面浏览器而言,viewport指的就是除去所有工具栏.状态栏.滚动条等等之后用于看网页的区域.对于传统WEB页面来说,9 ...

  7. Windows WMIC命令使用详解1

    https://blog.csdn.net/enweitech/article/details/51982114 在CMD和Powershell中 使用WMIC 先决条件: a. 启动Windows ...

  8. VR虚拟现实眼镜那些事

    今天是2014.3.20,笔者从oculus官网订了DK2(第二代开发版) 评测视频http://v.youku.com/v_show/id_XNjg3NTUzOTk2.html 想想从哪说起呢... ...

  9. CentOS6下安装Java jdk1.7.0_10和 maven

    安装步骤如下: 1. 下载JDK7.0_10 (jdk-7u10-linux-i586.tar.gz) 地址: 2. 卸载系统自带的开源JDK 查看是否安装JDK rpm -qa | grep jav ...

  10. js中match的用法

    match() 方法将检索字符串 stringObject,以找到一个或多个与 regexp 匹配的文本.这个方法的行为在很大程度上有赖于 regexp 是否具有标志 g. 一.如果 regexp 没 ...