这篇随笔是对上一篇随笔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. 关于在linux python源文件头部添加 “#!/usr/bin/env python” 不能直接运行的问题

    如果环境变量设置正确 如果文件是从windows拷贝到linux中的 可能是换行符造成的.试试dos2unix命令,或相似的命令,把dos格式的换行符转为unix格式.

  2. 1095 Cars on Campus (30)(30 分)

    Zhejiang University has 6 campuses and a lot of gates. From each gate we can collect the in/out time ...

  3. POJ1006Biorhythms——中国剩余定理

    题目:http://poj.org/problem?id=1006 用扩展欧几里得算法求逆元,使用中国剩余定理: 本题较简单,可以手算直接写出,不过我仍使用了模板. 代码如下: #include< ...

  4. Oracle创建表,并添加默认值和备注

    create table testemp( id varchar2(50) default sys_guid(),deptno varchar2(20) ,--部门编码 ename varchar2( ...

  5. Oracle分组后取某列最大值的行数据

    select * from ( select last_comment, row_number() over(partition by employeeid,roadline,stationname ...

  6. 14 vue学习 postcssrc eslintrc.js babelrc

    一  .postcssrc.js 众所周知为兼容所有浏览器,有的CSS属性需要对不同的浏览器加上前缀,然而有时添加一条属性,需要添加3~4条类似的属性只是为了满足浏览器的兼容,这不仅会增加许多的工作量 ...

  7. strlen("汉字")的值是多少

    转自:http://blog.csdn.net/gogor/article/details/4470775 strlen("汉字")的值是多少? 这个问题的答案与系统所采用的字符编 ...

  8. Spring:JdbcTemplate使用指南

    Spring:JdbcTemplate使用指南 Spring:JdbcTemplate使用指南 前言: 本文指在介绍Spring框架中的JdbcTemplate类的使用方法,涉及基本的Spring反转 ...

  9. 4.ctf实战题

    一道ctf实战题. 先亮出网址: http://fb2ad00f-0a28-4e38-8fff-849d7391e2d0.coding.io 打开连接,看到下面页面.Web题,首先就是扫描(御剑啊还有 ...

  10. gridview把textbox的值修改还是旧值的解决方法

    解决方法很简单,加上if(!IsPostBack) 就OK了,因为之前加载之前都会调用InitData(). protected void Page_Load(object sender, Event ...