你的位置:首页 > ASP.net教程

[ASP.net教程]C#中的yield return与Unity中的Coroutine(协程)(上)


C#中的yield return

C#语法中有个特别的关键字yield, 它是干什么用的呢?

来看看专业的解释:

yield 是在迭代器块中用于向枚举数对象提供值或发出迭代结束信号。它的形式为下列之一:
yield return <expression>;
yield break

 

看如下例子:

 

 1 1   public class CustomCollection :IEnumerable { 2 2      3 3     public static void Main (string[] args) 4 4     { 5 5       CustomCollection cc = new CustomCollection (); 6 6  7 7       foreach (String word in cc) { 8 8         Console.WriteLine ("word:" +word); 9 9       }10 10     }11 11 12 12     public IEnumerator GetEnumerator(){13 13 14 14       yield return "Hello";15 15       yield return "Boys";16 16       yield return "And";17 17       yield return "Girls";18 18       //return new HelloBoyGirls();19 19 20 20     }21 21   }22 22 23 23 //  public class HelloBoyGirls: IEnumerator {24 24 //    private int cusor = -1;25 25 //    private String[] words = {"Hello", "Boys", "And", "Girls"};26 26 //    27 27 //    public bool MoveNext ()28 28 //    {29 29 //      cusor++;30 30 //      return cusor < words.Length;31 31 //    }32 32 //33 33 //    public void Reset ()34 34 //    {35 35 //      cusor = 0;36 36 //    }37 37 //38 38 //    public object Current {39 39 //      get {40 40 //        return words [cusor];41 41 //      }42 42 //    }43 43 //  }

View Code

 

 

 

上面的例子是实现了一个自定义的迭代器;实现可迭代(可以用foreach)的数据集合,必须实现GetEmumerator()方法,返回实现了IEmumerator的对象实例。

完成这个, 有两种方法,一种是用上面注释掉的代码,一种是用yield return. yield return 需要配合IEmumerator进行使用, 在外部foreach循环中,它会执行GetEmumerator()方法,遇到yield return, 做了如下两件事情:

1.记录下当前执行到的代码位置

2. 将代码控制权返回到外部, yield return 后面的值, 作为迭代的当前值。

当执行下一个循环, 从刚才记录的代码位置后面, 开始继续执行代码。

简单地说, yield return 就是实现IEmumerator的超级简化版, 是不是很简单?

 

那么问题又来了, yield return 是如何决定循环该结束,yield return 之后的代码, 什么时候执行呢?

把上面的例子改造一下, 不要用方便的foreach了, 用while 循环自己控制:

 1   public class CustomCollection :IEnumerable { 2      3     public static void Main (string[] args) 4     { 5       CustomCollection cc = new CustomCollection (); 6  7       IEnumerator enumerator = cc.GetEnumerator (); 8       while (true) { 9         bool canMoveNext = enumerator.MoveNext ();10         Console.WriteLine ("canMoveNext:" +canMoveNext);11         if (!canMoveNext)12           break;13         Object obj = enumerator.Current;14         Console.WriteLine ("current obj:" +obj);15       }16 //      foreach (String word in cc) {17 //        Console.WriteLine ("word:" +word);18 //      }19       Console.WriteLine ("Main End.");20 21     }22 23     public IEnumerator GetEnumerator(){24 25       yield return "Hello";26       yield return "Boys";27       yield return "And";28       yield return "Girls";29 30       Console.WriteLine ("After all yield returns.");31       //return new HelloBoyGirls();32 33     }34   }

View Code

 

运行代码, 结果是:

canMoveNext:Truecurrent obj:HellocanMoveNext:Truecurrent obj:BoyscanMoveNext:Truecurrent obj:AndcanMoveNext:Truecurrent obj:GirlsAfter all yield returns.canMoveNext:FalseMain End.

说明, 在GetEmumerator()中, 只有yield return 语句, 外部调用MoveNext()都为true, current就是yield return后面的对象

除了yield return, 还有yield break; yield break 的作用是, 停止循环, MoveNext()为false, yield break 之后的语句, 不会被执行!

有兴趣的童鞋, 可以自己写个例子试试。