yield 关键字向编译器指示它所在的方法是迭代器块。编译器生成一个类来实现迭代器块中表示的行为。在迭代器块中,yield 关键字与 return 关键字结合使用,向枚举器对象提供值。这是一个返回值,例如,在 foreach 语句的每一次循环中返回的值。yield 关键字也可与 break 结合使用,表示迭代结束。
例子:
yield return <expression>;
yield break;
在 yield return 语句中,将计算 expression 并将结果以值的形式返回给枚举器对象;expression 必须可以隐式转换为 yield 类型的迭代器。
在 yield break 语句中,控制权将无条件地返回给迭代器的调用方,该调用方为枚举器对象的 IEnumerator.MoveNext 方法(或其对应的泛型 System.Collections.Generic.IEnumerable<T>)或 Dispose 方法。
yield 语句只能出现在 iterator 块中,这种块可作为方法、运算符或访问器的主体实现。这类方法、运算符或访问器的体受以下约束的控制:
-
不允许不安全块。
-
yield return 语句不能放在 try-catch 块中的任何位置。该语句可放在后跟 finally 块的 try 块中。
-
yield break 语句可放在 try 块或 catch 块中,但不能放在 finally 块中。
yield 语句不能出现在匿名方法中。有关更多信息,请参见匿名方法(C# 编程指南)。
当和 expression 一起使用时,yield return 语句不能出现在 catch 块中或含有一个或多个 catch 子句的 try 块中。
yield是C#为了简化遍历操作实现的语法糖,我们知道如果要要某个类型支持遍历就必须要实现系统接口IEnumerable,这个接口后续实现比较繁琐要写一大堆代码才能支持真正的遍历功能。举例说明
using System; using System.Collections.Generic; using System.Collections; using System.Linq; using System.Text; namespace { class Program { static void Main(string[] args) { HelloCollection helloCollection = new HelloCollection(); foreach (string s in helloCollection) { Console.WriteLine(s); } Console.ReadKey(); } } //public class HelloCollection : IEnumerable //{ // public IEnumerator GetEnumerator() // { // yield return "Hello"; // yield return "World"; // } //} public class HelloCollection : IEnumerable { public IEnumerator GetEnumerator() { Enumerator enumerator = new Enumerator(0); return enumerator; } public class Enumerator : IEnumerator, IDisposable { private int state; private object current; public Enumerator(int state) { this.state = state; } public bool MoveNext() { switch (state) { case 0: current = "Hello"; state = 1; return true; case 1: current = "World"; state = 2; return true; case 2: break; } return false; } public void Reset() { throw new NotSupportedException(); } public object Current { get { return current; } } public void Dispose() { } } } }
上面注释的部分引用了"yield return”,其功能相当于下面所有代码!可以看到如果不适用yield需要些很多代码来支持遍历操作。
yield return 表示在迭代中下一个迭代时返回的数据,除此之外还有yield break, 其表示跳出迭代,为了理解二者的区别我们看下面的例子
class A : IEnumerable { private int[] array = new int[10]; public IEnumerator GetEnumerator() { for (int i = 0; i < 10; i++) { yield return array[i]; } } }
如果你只想让用户访问ARRAY的前8个数据,则可做如下修改.这时将会用到yield break,修改函数如下
public IEnumerator GetEnumerator() { for (int i = 0; i < 10; i++) { if (i < 8) { yield return array[i]; } else { yield break; } } }