知识大全 foreach和yield
Posted 知
篇首语:五陵年少金市东,银鞍白马渡春风。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 foreach和yield相关的知识,希望对你有一定的参考价值。
foreach
foreach无需要知道集合中元素个数就可以迭代集合中的元素 它其实是迭代器模式的一个包装 就语言层面来说 是while的另一种形式
using System;
using System Collections;
public class People : IEnumerable//版本 string[] names; public People(string[] names) this names = names; public IEnumerator GetEnumerator() return new Enumerator(this names); private class Enumerator : IEnumerator private int state = ; string[] names; internal Enumerator(string[] names) this names = names; public bool MoveNext() state++; return (state < names Length); public void Reset() state = ; public object Current get try return names[state]; catch (IndexOutOfRangeException) throw new InvalidOperationException(); public class Test public static void Main() People people = new People(new string[] aaa bbb ccc ddd ); foreach (var person in people) Console WriteLine(person); IEnumerator Enumerator = people GetEnumerator(); while (Enumerator MoveNext()) Console WriteLine(Enumerator Current); 查看IL代码 先看foreach代码块的IL代码
IL_ f: callvirt instance class [mscorlib]System Collections IEnumerator People::GetEnumerator()
IL_ : stloc s CS$ $
try
IL_ : br s IL_
IL_ : ldloc s CS$ $
IL_ a: callvirt instance object [mscorlib]System Collections IEnumerator::get_Current()
IL_ f: stloc
IL_ : ldloc
IL_ : call void [mscorlib]System Console::WriteLine(object)
IL_ : ldloc s CS$ $
IL_ : callvirt instance bool [mscorlib]System Collections IEnumerator::MoveNext()
IL_ d: brtrue s IL_
IL_ f: leave s IL_
// end try
finally
IL_ : ldloc s CS$ $
IL_ : isinst [mscorlib]System IDisposable
IL_ : stloc s CS$ $
IL_ a: ldloc s CS$ $
IL_ c: brfalse s IL_
IL_ e: ldloc s CS$ $
IL_ : callvirt instance void [mscorlib]System IDisposable::Dispose()
IL_ : endfinally
// end handler再看while代码块的IL代码
IL_ : callvirt instance class [mscorlib]System Collections IEnumerator People::GetEnumerator()
IL_ : stloc
IL_ : br s IL_
IL_ : ldloc
IL_ a: callvirt instance object [mscorlib]System Collections IEnumerator::get_Current()
IL_ f: call void [mscorlib]System Console::WriteLine(object)
IL_ : ldloc
IL_ : callvirt instance bool [mscorlib]System Collections IEnumerator::MoveNext()
IL_ a: brtrue s IL_ 可以看出foreach语句块IL代码与while语句块的IL代码相比 只多了finally部分的资源处理 但循环部分的代码基本没有任何分别
如果让private class Enumerator 增加IDisposable接口 将while语句块改写为如下
using((IDisposable)Enumerator)
while (Enumerator MoveNext())
Console WriteLine(Enumerator Current);
得到的IL代码将与foreach基本没有区别
由此可见 foreach是编译器给我们的一个语法糖 它包装了while
yield
在上面的代码中枚举器private class Enumerator 是自己实现了IEnumerator接口中的方法 使用yield语句 可以让编译器自动实现 省去了自己写的麻烦(包含yield语句的方法或属性必须声明为返回IEnumerable 或IEnumerator ) 所以上面的public class People 可以这样写
public class People : IEnumerable//版本
string[] names;
public People(string[] names)
this names = names;
public IEnumerator GetEnumerator()
for (int i = ; i < names Length; i++)
yield return names[i];
反编译之后 看IL代码
这是版本 people类
这是版本 的people类
自己写的迭代器类Enumerator和编译器生成的迭代器类<GetEnumerator>d_ 相比较 <GetEnumerator>d_ 增加了IDisposable接口 另外就是增加了IEnumerator接口的泛型版本的继承 如果愿意 Enumerator也可以实现这两个接口
用yield还可以返回IEnumerable接口类型
using System;
using System Collections;
public class People
string[] names;
public People(string[] names)
this names = names;
public IEnumerable PeopleEven()
for (int i = ; i < names Length; i += )
yield return names[i];
public class Test
public static void Main()
People people = new People(new string[] aaa bbb ccc ddd );
foreach (var person in people PeopleEven())
Console WriteLine(person);
该PeopleEven()返回的IEnumerable类<PeopleEven>d_ 会自动实现GetEnumerator()方法和IEnumerator接口中的方法 看IL代码
PeopleEven()返回的类<PeopleEven>d_ 实现了IEnumerable和IEnumerator接口以及它们的泛型版本 还实现了IDisposable接口 因此 可以将这 个接口都实现 将类改写
using System;
using System Collections;
public class People : IEnumerable IEnumerator IDisposable
string[] names = bbbb dddd ;
int state = ;
public IEnumerator GetEnumerator()
return new People();
public bool MoveNext()
state++;
return (state < names Length);
public void Reset()
state = ;
public object Current
get
try
return names[state];
catch (IndexOutOfRangeException)
throw new InvalidOperationException();
public void Dispose()
public class Test
public static void Main()
People people = new People();
foreach (var person in people)
Console WriteLine(person);
看IL代码
类People与PeopleEven()返回的类<PeopleEven>d_ 基本相同 只是少了两个接口的泛型版本的实现
由此可见 yield是一个更大的语法糖 它可以自动实现IEnumerable和IEnumberator接口中的方法 自动替我们实现迭代器
cha138/Article/program/net/201311/11643相关参考
foreach通过在$value之前加上&很容易就能修改数组的单元如PHP代码foreach($arr as &$value)  
C#中foreach基础使用方法 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 昨天做老师的网站
//foreach $tar=array( =>东 =>西 =>南 =>北 =>东南 =>西南 =>东北 =>西北 =>南
C#中foreach基础使用方法[1] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 昨天做老师
C#中foreach基础使用方法[2] 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 就是像开头
知识大全 php遍历数组 list foreach each方法总结
在php中可以用来遍历数组的函数有很多如有for语句listeachforeach这四个函数这也是在php中遍历数组的几个主要的函数下面我来给大家介绍 foreach遍历数组我们在运用数组时
知识大全 jsp简单自定义标签的forEach遍历及转义字符
jsp简单自定义标签的forEach遍历及转义字符 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!l
知识大全 如何在smarty中增加类似foreach的功能自动加载数据
在smarty中使用自定义插件来加载数据(见编写Smarty插件在模板中直接加载数据的详细介绍)在使用的时候还是感觉不够方便灵机一动就想写成类似foreach那种标签第一步在Smarty_Comp
知识大全 Smarty foreach控制循环次数的实现详解
Smartyforeach控制循环次数的实现详解 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!在s
staticvoidMain(string[]args) int[]myNum=newint[]; myNum=GetRand(); ArraySort(myNum); foreach