c#中Iterator的实现和其他

原文地址在这里
虽然是很老的文章,但是这个博客内容里,有很多很有用的内容。

前言

迭代器,Iterator很多语言中都有的概念,对应C#中比如IEnumerable类。

C#中的Iterator是一个复杂的语法糖,在定义一个Iterator时,一般通过一个含有yield return的函数来实现。

这背后的思想是,这个Iterator以及和它有关的变量,都被编译器封装在了一个Helper类中,在这个Helper类中,还会维护一个State状态变量,维护当前Iterator上次使用的状态。

说明

比如如下代码中,CountFrom返回一个从startlimit的int型iterator。

class MyClass {
    int limit = 0;
    public MyClass(int limit) {
        this.limit = limit;
    }
    public IEnumerable<int> CountFrom(int start)
    {
        for (int i = start; i <= limit; i++) {
            yield
            return i;
        }
    }
}

编译器会将CountFrom转换为一个Helper类,而其内部有一个状态机:

 class MyClass_Enumerator: IEnumerable < int > {
     int state$0 = 0; // internal member
     int current$0; // internal member
     MyClass this$0; // implicit parameter to CountFrom
     int start; // explicit parameter to CountFrom
     int i; // local variable of CountFrom
     public int Current {
         get {
             return current$0;
         }
     }
     public bool MoveNext()
     {
         switch (state$0) {
             case 0:
                 goto resume$0;
             case 1:
                 goto resume$1;
             case 2:
                 return false;
         }
         resume$0: ;
         for (i = start; i <= this$0.limit; i++) {
             current$0 = i;
             state$0 = 1;
             return true;
             resume$1: ;
         }
         state$0 = 2;
         return false;
     }
     ......
     下面还有一些在这里无关紧要的代码…
 }
 public IEnumerable<int> CountFrom(int start)
 {
     MyClass_Enumerator e = new MyClass_Enumerator();
     e.this$0 = this;
     e.start = start;
     return e;
 }

其中:

  • start$0,current$0是内部变量维护
  • starti是实际遍历使用的变量
  • state$0resume$0/1/..维护了当前iterator的执行状态,有执行过程中,执行开始,执行结束
    • 这里如果原iterator有多个yield return,那么相应的状态result$n也会增加

实际的逻辑,就写在MyClass_Enumerator类的MoveNext中,每次向前取值后,通过Current返回当前值。
下次再次进入时,由于内部类保证了状态,可以从上一次开始继续取值。

这种内部类的方法,相比较递归方式,更节省栈空间,因为类是分配在堆上的。

其他补充

这种通过yield return+状态机的思想,也是后面c#异步编程async await等的一种思想。
通过一个helper类,记录之前的状态,下次进入直接从之前的状态执行

猜你喜欢

转载自www.cnblogs.com/mosakashaka/p/12804832.html