在foreach语句中使用枚举,可以迭代数组或集合中的元素,且无须知道集合中的元素的个数。如图显示了调用foreach方法的客户端和集合之间的关系。数组或集合实现带GetEnumerator()方法的IEnumerable接口。GetEnumerator()方法返回一个实现lEnumerable接口的枚举,接着foreach语句就可以使用IEnumerable接口迭代集合了。

GetEnumerator()方法用IEnumerable接口定义,foreach语句并不真的需要在集合类中实现这个接口。有一个名为GetEnumerator()的方法它返回实现了IEnumerator接口的对象就足够了。

先定义一个Person类,这个类有自动实现的属性Firstname和Lastname,以及从Object类重写ToString方法和继承泛型接口IEquatable以比较两个对象是否相等,实现泛型接口IComparer以比较两个对象用来排序。

public class Person : IEquatable<Person>,IComparable<Person>
{
public int Id { get; private set; }
public string FirstName { get; set; }
public string LastName { get; set; } public override string ToString()
{
return String.Format("{0}, {1} {2}", Id, FirstName, LastName);
} public bool Equals(Person other)
{
if (other == null)
return base.Equals(other); return this.FirstName == other.FirstName && this.LastName == other.LastName;
} public int CompareTo(Person other)
{
if (other == null) throw new ArgumentNullException("other"); int result = this.LastName.CompareTo(other.LastName);
if (result == )
{
result = this.FirstName.CompareTo(other.FirstName);
} return result;
} }

创建一个三个元素的person数组,现对数组进行排序在用foreach循环访问数组中的元素并输出

 Person[] persons = {
new Person { FirstName = "Simen03", LastName = "Go" },
new Person { FirstName = "Simen02", LastName = "Go" },
new Person { FirstName = "Simen01", LastName = "Go" }
};
Array.Sort(persons);
foreach (var person in persons)
Console.WriteLine(person);

分析foreach (var person in persons)Console.WriteLine(person);这段代码IL代码

// loop start (head: IL_009b)
IL_008a: ldloc.
IL_008b: ldloc.
IL_008c: ldelem.ref
IL_008d: stloc.s person
IL_008f: ldloc.s person
IL_0091: call void [mscorlib]System.Console::WriteLine(object)
IL_0096: nop
IL_0097: ldloc.
IL_0098: ldc.i4.
IL_0099: add
IL_009a: stloc. IL_009b: ldloc.
IL_009c: ldloc.
IL_009d: ldlen
IL_009e: conv.i4
IL_009f: blt.s IL_008a
// end loop

C#的foreach语句不会解析为IL代码中的foreach语句,C#编译器会把foreach语句转换为IEnumerable接口的方法和属性,foreach语句使用IEnumerator接口的方法和属性,迭代数组中的所有元素,为此,IEnumerator定义了Current属性,来返回光标所在的元素,该接口的MoveNext()方法移动到数组的下一个元素上,如果有这个元素该方法就返回true否则返回false,这个接口的泛型版本IEnumerator派生自接口IDisposable,因此定义了Dispose()方法来清理枚举器占用的资源,使用foreach语句会解析为下面的代码段

 IEnumerator enumerator = persons.GetEnumerator();
while (enumerator.MoveNext())
{
var person = enumerator.Current;
Console.WriteLine(person);
}

为了方便的创建枚举器,C#添加了yield语句,yield return 语句返回集合的一个元素,并移动到下一个元素,yield break 可停止迭代。使用迭代块,编译器会生成一个yield类型,其中包含一个状态机,如下代码段所示。yield 类型实现IEnumerator和IDisposable接口的属性和方法。在下面的例子中,可以把yield类型看作内部类Enumerator.外部类的GetEnumerator()方法实例化并返回一个新的yield类型。在yield类型中,变量state定义了迭代的当前位置,每次调用MoveNext()时,当前位置都会改变,MoveNext()封装了迭代代码,并设置了current变量的值,从而使Current属性根据位置返回一个对象。

 static void Main(string[] args)
{
var helloCollection = new HelloCollection();
foreach (string s in helloCollection)
{
Console.WriteLine(s);
}
} public class HelloCollection
{
public IEnumerator<string> GetEnumerator()
{
yield return "Hello";
yield return "World";
}
}
public class HelloCollectionOther
{
public IEnumerator GetEnumertor()
{
return new Enumerator();
}
public class Enumerator : IEnumerator<string>, IEnumerator, IDisposable
{
private int state;
private string current;
public Enumerator(int state)
{
this.state = state;
} public string Current => throw new NotImplementedException(); object IEnumerator.Current
{
get { return current; }
} public void Dispose()
{
throw new NotImplementedException();
} public bool MoveNext()
{
switch (state)
{
case :current = "hello";
state = ;
return true;
case :current = "world";
state = ;
return true;
case :
break;
}
return false;
} public void Reset()
{
throw new NotImplementedException();
}
}
}

从foreach语句枚举元素看数组的更多相关文章

  1. PHP:第二章——PHP中的foreach语句

    foreach语句提供了遍历数组的 <?php header("Content-Type:text/html;charset=utf-8"); $arr=array(&quo ...

  2. C#中的foreach语句与枚举器接口(IEnumerator)及其泛型 相关问题

    这个问题从<C#高级编程>数组一节中的foreach语句(6.7.2)发现的. 因为示例代码与之前的章节连贯,所以我修改了一下,把自定义类型改为了int int[] bs = { 2, 3 ...

  3. 为什么数组没有实现Iterable接口,但可以使用foreach语句遍历

    在Java中,对于数组为什么能够使用foreach语句一直感觉很困惑. 对于能够使用foreach语句进行遍历的对象,只有两种情况,其中一种是遍历对象必须实现Iterable接口,实现ierator( ...

  4. Java使用foreach语句对数组成员遍历输出

    /** * 本程序使用foreach语句对数组成员进行遍历输出 * @author Lei * @version 2018-7-23 */ public class ForeachDemo { pub ...

  5. 使用foreach语句对数组成员进行遍历

    /*** 使用foreach语句对数组成员进行遍历* **/ public class ForeachDemo { public static void main(String[] args) { i ...

  6. foreach语句

    foreach语句他无非就是for循环的封装,为了提高开发速度才创造出来的.他其实跟for循环一样,只不过写起来比较简便,他是1.5版本才出来的一种封装语法.并没有什么奇特之处他里面的机制就是for循 ...

  7. 可迭代的集合类型使用foreach语句

    在学习算法这本书图论那一部分的时候,接触到了几个类似for(int w:G.adj(v)),的语句,不是很理解,就去百度,发现这是一种叫做foreach的语法,在书的76页有讲到,但是之前没认真看书, ...

  8. 自定义一个可以使用foreach语句进行迭代的类(IEnumerable)

    在c#中,凡是实现了IEnumerable接口的数据类型都可以用foreach语句进行迭代访问.所以,我们要定义一个可以使用foreach进行迭代访问的类,就必须要实现IEnumerable接口. / ...

  9. 浅析foreach语句

    本篇是我对于foreach语句(增强for)的总结: 我的总结流程如下: 1.先整体说明增强for遍历集合与数组之间的区别. 2.通过一维数组来说明(给出反编译的源码,形成对照). 3.通过二维数组来 ...

随机推荐

  1. IIS 部署ASP.Net, WebAPI, Restful API, PUT/DELETE 报405错解决办法, webapi method not allowed 405

    WebDAV 是超文本传输协议 (HTTP) 的一组扩展,为 Internet 上计算机之间的编辑和文件管理提供了标准.利用这个协议用户可以通过Web进行远程的基本文件操作,如拷贝.移动.删除等.在I ...

  2. (17)IO中的异常处理

    public static void copyImage() throws IOException { //找到目标文件 File inFile = new File("D:\\1.jpg& ...

  3. 解决HTML textarea 标签出现大量空格

    就是什么内容也不写,然后前面却有一堆空格 原因是 textarea标签换行了 <textarea cols=" id="serve_content" name=&q ...

  4. 【SF】开源的.NET CORE 基础管理系统 -介绍篇

    [SF]开源的.NET CORE 基础管理系统 -系列导航 1.环境: .NET Core SDK (https://www.microsoft.com/net/core) SQL Server or ...

  5. 关于window service2008系统iis部署访问证书,内部错误

    近期因为在做微信支付系列,做到退款的时候需要通过把数据流通过证书post过去的时候,win7.win8.xp部署在iis都没问题.但是部署到服务器 2008的时候就出现了内部错误. 折腾许久,总算找到 ...

  6. flex中创建弹出窗口,并传值

    在flex页面中首先创建一个弹出窗口,代码如下: <?xml version="1.0" encoding="utf-8"?> <s:Titl ...

  7. windos环境apache+mysql+php+Discuz的安装配置

    首先是相关软件的下载:PHP.Apache和Mysql软件以及VC库.相关软件可到我的百度网盘下载,百度网盘:http://pan.baidu.com/s/1o6DYcMu 相关软件的直接下载地址: ...

  8. impress.js初体验

    概述 如果你已经厌烦了使用PowerPoint制作PPT,那么impress.js是一个非常好的选择,用它做的PPT更加直观,效果也非常的不错.装X是需要一定代价的,不过如果你是个前端爱好者那么一切就 ...

  9. Linux下的文件描述符

    文件描述符是一个简单的整数,用以标明每一个被进程所打开的文件和socket.第一个打开的文件是0,第二个是1,依此类推.Unix 操作系统通常给每个进程能打开的文件数量强加一个限制.更甚的是,unix ...

  10. opencv配置(win10+VS2015+opencv3.1)

    Step 1:准备工作 a.win10 b.vs2015 c.opencv3.1[从http://opencv.org/downloads.html下载] Step 2.开始安装 a. 双击openc ...