知识大全 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使用引用注意的问题

  foreach通过在$value之前加上&很容易就能修改数组的单元如PHP代码foreach($arr as &$value)   

知识大全 C#中foreach基础使用方法

C#中foreach基础使用方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  昨天做老师的网站

知识大全 php foreach与for语句用法区别介绍

  //foreach  $tar=array(  =>东  =>西  =>南  =>北  =>东南  =>西南  =>东北  =>西北  =>南

知识大全 C#中foreach基础使用方法[1]

C#中foreach基础使用方法[1]  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  昨天做老师

知识大全 C#中foreach基础使用方法[2]

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