Foreach遍历
前天在项目中遇到一个问题,foreach遍历过程中修改responses中的对象,其中responses的类型:IEnumerable<Order>,代码如下:
foreach (Order item in responses)
{
if (string.IsNullOrEmpty(item.Creator))
item.Creator = item.Creator2;
}
结果可想而知,response的对象并没有被改变。这是为什么?
弄清楚问题之前需要明白什么是foreach。foreach语句为数组或者对象集合的每一个元素重复一个嵌入语句组,foreach语句用于循环访问集合以获取所需信息,但不应更改集合信息以避免不可预知的负作用。(百度百科)Foreach可以循环访问集合以获取所需信息,为什么foreach不能更改集合信息,什么样的对象能够foreach?这就涉及到IEnumerable和IEnumerator.
IEnumerable和IEnumerator是两个用来实现枚举的接口,相互协助来完成一个具有枚举功能能使用foreach的集合。IEnumerable是一个声明性接口,一个集合对象要foreach,必须实现IEnumerable接口,也既是必须以某种方式返回IEnumerator object。IEnumerator是一个实现式接口,它定义了具体的实现方法。下面首先介绍其定义:
定义IEnumerator接口:
public interface IEnumerator
{
object Current{ get; } bool MoveNext();
void Reset();
}
定义IEnumerable接口:
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
了解定义后,下面实例具体实现IEnumerable和IEnumerator:
public class MyIEnumerator : IEnumerator
{
private string[] strList;
private int position; public MyIEnumerator(string[] strList)
{
this.strList = strList;
position = -;
} public object Current
{
get { return strList[position]; }
} public bool MoveNext()
{
position ++;
if (position < strList.Length) return true;
return false;
} public void Reset()
{
position = -;
}
}
public class MyIEnumerable : IEnumerable
{
private string[] strList; public MyIEnumerable(string[] strList)
{
this.strList = strList;
}
public IEnumerator GetEnumerator()
{
return new MyIEnumerator(strList);
}
}
进行调用:
string[] strList = {"", "", "", ""};
MyIEnumerable my = new MyIEnumerable(strList);
var tt = my.GetEnumerator();
while (tt.MoveNext())
{
Console.Write("{0} ", tt.Current);
}
结果如下:

那么在项目中,如何自定义一个类实现foreach,继承IEnumerable即可,如下实例:
定义实体类:
public class Student
{
public int Id;
public string Name; public Student(int id, string name)
{
Id = id;
Name = name;
}
}
定义student的集合类School,继承IEnumerable集合:
public class School : IEnumerable
{
public Student[] stu = new Student[]; public School()
{
Create();
} public void Create()
{
stu[] = new Student(, "tom");
stu[] = new Student(, "john");
stu[] = new Student(, "mali");
} public IEnumerator GetEnumerator()
{
return this.stu.GetEnumerator();
}
}
使用foreach遍历school:
School school = new School();
foreach (Student item in school.stu)
{
Console.WriteLine("Id is {0} ,Name is {1}", item.Id, item.Name);
}
foreach (Student item in school)
{
Console.WriteLine("Id is {0} ,Name is {1}", item.Id, item.Name);
}
结果如下:

此时一个概念“迭代器”应该进入大家的视野。
迭代器是一种对象,它能够用来遍历标准模板库容器的部分或者全部元素,每个迭代器对象代表容器中的确定地址。
迭代器使开发人员能够在类或者结构中支持foreach迭代,而不必整个实现IEnumerable和IEnumerator接口。只需要提供一个迭代器,即可遍历类中的数据结构。当编译器检测到迭代器时,将自动生成IEnumerable和IEnumerator接口中的相应方法。
另外一个概念yield:yield关键字向编译器指示它所在的方法是迭代器。编译器生成一个类来实现迭代器块中表示的行为。在迭代器块中,yield关键字与return关键字结合使用,向枚举器对象提供值。yield关键字也可与break结合使用,表示迭代结束。
引用:
IEnumerable 使用foreach 详解
IEnumerator和IEnumerable的关系
先说IEnumerable,我们每天用的foreach你真的懂它吗?
Foreach遍历的更多相关文章
- 用<forEach>遍历list集合时,提示我找不到对象的属性
<c:forEach items="${list}" var="item"> <tr> <td>${item.UserId} ...
- 使用yield关键字让自定义集合实现foreach遍历
一般来说当我们创建自定义集合的时候为了让其能支持foreach遍历,就只能让其实现IEnumerable接口(可能还要实现IEnumerator接口) 但是我们也可以通过使用yield关键字构建的迭代 ...
- js中三个对数组操作的函数 indexOf()方法 filter筛选 forEach遍历 map遍历
indexOf()方法 indexOf()方法返回在该数组中第一个找到的元素位置,如果它不存在则返回-1. 不使用indexOf时 var arr = ['apple','orange','pea ...
- mybatis map foreach遍历
mybatis map foreach遍历 转至http://www.cnblogs.com/yg_zhang/p/4314602.html mybatis 遍历map实例 map 数据如下 Map& ...
- foreach遍历遇到的一个细节问题
1.Invalid argument supplied for foreach()警告错误解决办法:foreach遍历之前添加is_array()判断
- IEnumerable 接口 实现foreach 遍历 实例
额 为啥写着东西? 有次面试去,因为用到的时候特别少 所以没记住, 这个单词 怎么写! 经典的面试题: 能用foreach遍历访问的对象的要求? 答: 该类实现IEnumetable 接口 声明 ...
- 实现Foreach遍历
实现Foreach遍历的集合类,需要实现IEnumerable接口,泛型集合则需要实现IEnumerable<T>接口 using System; using System.Collect ...
- foreach遍历扩展(二)
一.前言 假设存在一个数组,其遍历模式是根据索引进行遍历的:又假设存在一个HashTable,其遍历模式是根据键值进行遍历的:无论哪种集合,如果它们的遍历没有一个共同的接口,那么在客户端进行调用的时候 ...
- c#--foreach遍历的用法与split的用法
一. foreach循环用于列举出集合中所有的元素,foreach语句中的表达式由关键字in隔开的两个项组成.in右边的项是集合名,in左边的项是变量名,用来存放该集合中的每个元素. 该循环 ...
随机推荐
- 测试Oracle 11gr2 RAC 非归档模式下,offline drop数据文件后的数据库的停止与启动测试全过程
测试Oracle 11gr2 RAC 非归档模式下,offline drop数据文件后的数据库的停止与启动测试全过程 最近系统出现问题,由于数据库产生的日志量太大无法开启归档模式,导致offline的 ...
- 环境变量/path/classpath/JAVA_HOME/JAVA环境变量配置
环境变量 环境变量是在操作系统中一个具有特定名字的对象,它包含了一个或者多个应用程序所将使用到的信息.例如Windows和DOS操作系统中的path环境变量,当要求系统运行一个程序而没有告诉它程序所在 ...
- IBatis.Net使用总结(三)-- IBatis实现分页返回数据和总数
IBatis 分页,这里没有使用其他插件,只使用最原始的方法. 输入参数: int currentPage 当前页 int pageSize 每页大小 Hashtable findCondition ...
- IDF实验室:倒行逆施
简单的PE文件逆向(.exe-IDA) 下载下来文件之后发现是一个exe文件,运行以后发现.
- hdu 5677 ztr loves substring 多重背包
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission( ...
- iOS ---不一样的NSLog打印(精准打印)
在iOS开发过程中,调试是很重要的过程,而除了各种断点调试(普通断点.条件断点.全局断点)之外,似乎NSLog是我们调试最常用的方法,当然,也是最简单朴素的寻debug方法. 在项目中,我们常使用的N ...
- nodejs 提示‘xxx’ 不是内部或外部命令解决方法
本文介绍了node.js包管理工具npm安装模块后,无法通过命令行执行命令,提示‘xxx’ 不是内部或外部命令的解决方法,给需要的小伙伴参考下. 一般出现这样的问题原因是npm安装出现了问题,全局 ...
- 弹性盒子布局flexbox
弹性盒子display:flexbox一般应用于父元素的容器上,然后对子元素来进行弹性布局 设置了flexbox的父元素不能设置具体的宽度与高度的值,而是通过子元素来设置值,父元素弹性的包裹既可 相关 ...
- JavaScript函数表达式
函数表达式的基本语法形式 var functionName = function(arguments){ //函数体 } 递归建议 我们通过例子来一步步说明,递归的最佳实现方式.下面是普通递归调用的例 ...
- maven ClassNotFoundException: org.springframework.web.context.ContextLoaderL
信息: Starting Servlet Engine: Apache Tomcat/6.0.32 2012-3-31 9:39:40 org.apache.catalina.core.Standar ...