• 迭代器基础知识


        以前用集合的时候,用foreach进行循环,也没深究里面的实现机制。昨日在博客园上看一大牛的文章,讲述yield return的问题,才知道原来是这样的啊。下面这些概念都摘抄自书上。

    1. 基础知识

    IEnumerable接口允许使用foreach循环,很多的集合类都实现这个接口,在foreach循环中,并不一定只能用集合类,可以定制类。简述下foreach循环中,迭代一个collectionObject集合的过程如下:

    1)调用collectionObject.GetEnumerator(),返回一个IEnumerator引用。这个方法可以通过IEnumerator接口的实现代码来获得,可选的。

    2)调用所返回的IEnumerator接口的movenext方法。

    3)如果movenext方法返回为true,就使用IEnumerator接口的current属性来回去对象的一个引用,用于foreach循环。

    4)重复前面两步,知道movenexr方法返回false为止。直至循环结束。

    使用迭代器的两个类型的场合是:

    1)如果要迭代一个类,可使用方法GetEnumerator(),其返回类型是IEnumerator

    2)如果要迭代一个类成员,例如一个方法,则使用IEnumerable。

    2 实例

    举例说明

    1)迭代一个类成员

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Text;
     4 using System.Collections;
     5 namespace Ch12Ex01
     6 {
     7     class Program
     8     {
     9  public static IEnumerable GetList()
    10         {
    11             Console.WriteLine("GetList  Method");
    12             yield return "string1";
    13             yield return "string2";
    14             yield return "string3";
    15         }
    16         static void Main(string[] args)
    17         {
    18  var str = GetList();
    19             Console.WriteLine("Main method");
    20             foreach (string temp in str)
    21             {
    22                 Console.WriteLine(temp);
    23             }
    24     Console.ReadKey();
    25 
    26         }
    27     }
    28 }
    View Code

    注意这里,getlist方法在调用的时候并没有运行方法体的内容,而是在迭代的时候才运行。所以输出的结果是先输出main method,在输出getlist method。

    2)迭代一个类

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Text;
     4 using System.Collections;
     5 using System.Collections.Generic;
     6 namespace Ch12Ex01
     7 {
     8     class Primes
     9     {
    10         private int min;
    11         private int max;
    12         public Primes() : this(2, 100) { }
    13         public Primes(int minT, int maxT)
    14         {
    15             if (minT < 2) min = 2;
    16             else
    17             min = minT;
    18             max = maxT;
    19         }
    20         public IEnumerator GetEnumerator()
    21         {
    22             for (int i = min; i < max;i++ )
    23             {
    24                 if (i % 2 == 0 && i % 3 == 0)
    25                 {
    26                     yield return i;
    27                 }
    28             }
    29         }
    30     }
    31 }
    32 
    33   static void Main(string[] args)
    34         {
    35             Primes primes = new Primes(1, 1000);
    36             foreach (var a in primes)
    37             {
    38                 Console.WriteLine(a);
    39             }
    40             Console.ReadKey();
    41 
    42         }
    View Code

    3 内部实现机制

    1)GetList反编译。

      1 internal class Program
      2 {
      3     // Methods
      4     public static IEnumerable GetList()
      5     {
      6         return new <GetList>d__0(-2);
      7     }
      8 
      9     private static void Main(string[] args)
     10     {
     11         IEnumerable list = GetList();
     12         Console.WriteLine("Main method");
     13         foreach (string str in list)
     14         {
     15             Console.WriteLine(str);
     16         }
     17         Console.ReadKey();
     18     }
     19 
     20     // Nested Types
     21     [CompilerGenerated]
     22     private sealed class <GetList>d__0 : IEnumerable<object>, IEnumerable, IEnumerator<object>, IEnumerator, IDisposable
     23     {
     24         // Fields
     25         private int <>1__state;
     26         private object <>2__current;
     27         private int <>l__initialThreadId;
     28 
     29         // Methods
     30         [DebuggerHidden]
     31         public <GetList>d__0(int <>1__state)
     32         {
     33             this.<>1__state = <>1__state;
     34             this.<>l__initialThreadId = Thread.CurrentThread.ManagedThreadId;
     35         }
     36 
     37         private bool MoveNext()
     38         {
     39             switch (this.<>1__state)
     40             {
     41                 case 0:
     42                     this.<>1__state = -1;
     43                     Console.WriteLine("GetList  Method");
     44                     this.<>2__current = "string1";
     45                     this.<>1__state = 1;
     46                     return true;
     47 
     48                 case 1:
     49                     this.<>1__state = -1;
     50                     this.<>2__current = "string2";
     51                     this.<>1__state = 2;
     52                     return true;
     53 
     54                 case 2:
     55                     this.<>1__state = -1;
     56                     this.<>2__current = "string3";
     57                     this.<>1__state = 3;
     58                     return true;
     59 
     60                 case 3:
     61                     this.<>1__state = -1;
     62                     break;
     63             }
     64             return false;
     65         }
     66 
     67         [DebuggerHidden]
     68         IEnumerator<object> IEnumerable<object>.GetEnumerator()
     69         {
     70             if ((Thread.CurrentThread.ManagedThreadId == this.<>l__initialThreadId) && (this.<>1__state == -2))
     71             {
     72                 this.<>1__state = 0;
     73                 return this;
     74             }
     75             return new Program.<GetList>d__0(0);
     76         }
     77 
     78         [DebuggerHidden]
     79         IEnumerator IEnumerable.GetEnumerator()
     80         {
     81             return this.System.Collections.Generic.IEnumerable<System.Object>.GetEnumerator();
     82         }
     83 
     84         [DebuggerHidden]
     85         void IEnumerator.Reset()
     86         {
     87             throw new NotSupportedException();
     88         }
     89 
     90         void IDisposable.Dispose()
     91         {
     92         }
     93 
     94         // Properties
     95         object IEnumerator<object>.Current
     96         {
     97             [DebuggerHidden]
     98             get
     99             {
    100                 return this.<>2__current;
    101             }
    102         }
    103 
    104         object IEnumerator.Current
    105         {
    106             [DebuggerHidden]
    107             get
    108             {
    109                 return this.<>2__current;
    110             }
    111         }
    112     }
    113 }
    View Code

    从上面看到编译器生成了一个密封类,类名为<GetList>d__0,在main函数中调用getlist方法,其实只是新建了一个<GetList>d__0对象,当迭代的时候,才执行具体的内容,这也就能解释为啥先输出main method,再输出getlist method。

    2)将Prime类进行反编译,如下。

      1 internal class Primes
      2 {
      3     // Fields
      4     private int max;
      5     private int min;
      6 
      7     // Methods
      8     public Primes() : this(2, 100)
      9     {
     10     }
     11 
     12     public Primes(int minT, int maxT)
     13     {
     14         if (minT < 2)
     15         {
     16             this.min = 2;
     17         }
     18         else
     19         {
     20             this.min = minT;
     21         }
     22         this.max = maxT;
     23     }
     24 
     25     public IEnumerator GetEnumerator()
     26     {
     27         <GetEnumerator>d__0 d__ = new <GetEnumerator>d__0(0);
     28         d__.<>4__this = this;
     29         return d__;
     30     }
     31 
     32     // Nested Types
     33     [CompilerGenerated]
     34     private sealed class <GetEnumerator>d__0 : IEnumerator<object>, IEnumerator, IDisposable
     35     {
     36         // Fields
     37         private int <>1__state;
     38         private object <>2__current;
     39         public Primes <>4__this;
     40         public int <i>5__1;
     41 
     42         // Methods
     43         [DebuggerHidden]
     44         public <GetEnumerator>d__0(int <>1__state)
     45         {
     46             this.<>1__state = <>1__state;
     47         }
     48 
     49         private bool MoveNext()
     50         {
     51             switch (this.<>1__state)
     52             {
     53                 case 0:
     54                     this.<>1__state = -1;
     55                     this.<i>5__1 = this.<>4__this.min;
     56                     while (this.<i>5__1 < this.<>4__this.max)
     57                     {
     58                         if (((this.<i>5__1 % 2) != 0) || ((this.<i>5__1 % 3) != 0))
     59                         {
     60                             goto Label_0080;
     61                         }
     62                         this.<>2__current = this.<i>5__1;
     63                         this.<>1__state = 1;
     64                         return true;
     65                     Label_0078:
     66                         this.<>1__state = -1;
     67                     Label_0080:
     68                         this.<i>5__1++;
     69                     }
     70                     break;
     71 
     72                 case 1:
     73                     goto Label_0078;
     74             }
     75             return false;
     76         }
     77 
     78         [DebuggerHidden]
     79         void IEnumerator.Reset()
     80         {
     81             throw new NotSupportedException();
     82         }
     83 
     84         void IDisposable.Dispose()
     85         {
     86         }
     87 
     88         // Properties
     89         object IEnumerator<object>.Current
     90         {
     91             [DebuggerHidden]
     92             get
     93             {
     94                 return this.<>2__current;
     95             }
     96         }
     97 
     98         object IEnumerator.Current
     99         {
    100             [DebuggerHidden]
    101             get
    102             {
    103                 return this.<>2__current;
    104             }
    105         }
    106     }
    107 }
    View Code

    结合上面基础知识部分,就能知道迭代器的工作原理。每次迭代,其实就是执行movenext方法。

  • 相关阅读:
    line
    同步fifo的verilogHDL设计实例
    在DE1-SOC上运行Linux
    DE1-SOC连接设定
    Tcl语言笔记之二
    Tcl语言笔记之一
    关于复位赋初值的问题
    Altera FPGA中的pin进一步说明
    Altera FPGA中的pin简介
    笔记之Cyclone IV第一卷第四章Cyclone IV器件中的嵌入式乘法器
  • 原文地址:https://www.cnblogs.com/icbcfang/p/4390122.html
Copyright © 2020-2023  润新知