yield(C# 参考)
如果你在语句中使用 yield 关键字,则意味着它在其中出现的方法、运算符或 get 访问器是迭代器。通过使用 yield 定义迭代器,可在实现自定义集合类型的 IEnumerable 和 IEnumerator 模式时无需其他显式类(保留枚举状态的类,有关示例,请参阅 IEnumerator<T>)。
下面的示例演示了 yield 语句的两种形式。
yield return <expression>;
yield break;
备注
使用 yield return 语句可一次返回一个元素。
通过 foreach 语句或 LINQ 查询来使用迭代器方法。 foreach 循环的每次迭代都会调用迭代器方法。迭代器方法运行到 yield return 语句时,会返回一个 expression,并保留当前在代码中的位置。 当下次调用迭代器函数时执行从该位置重新启动。
可以使用 yield break 语句来终止迭代。
有关迭代器的详细信息,请参阅迭代器(C# 和 Visual Basic)。
迭代器方法和 get 访问器
迭代器的声明必须满足以下要求:
返回类型必须为 IEnumerable、IEnumerable<T>、IEnumerator 或 IEnumerator<T>。
该声明不能有任何 ref 或out https://msdn.microsoft.com/zh-CN/library/t3c3bfhx.aspx 参数。
返回 IEnumerable 或 IEnumerator 的迭代器的 yield 类型为 object。如果迭代器返回 IEnumerable<T> 或 IEnumerator<T>,则必须将 yield return 语句中的表达式类型隐式转换为泛型类型参数。
你不能在具有以下特点的方法中包含 yield return 或 yield break 语句:
匿名方法。有关详细信息,请参阅匿名方法(C# 编程指南)。
包含不安全的块的方法。有关详细信息,请参阅unsafe(C# 参考)。
异常处理
不能将 yield return 语句置于 try-catch 块中。可将 yield return 语句置于 try-finally 语句的 try 块中。
yield break 语句可以位于 try 块或 catch 块,但不能位于 finally 块。
如果 foreach 主体(在迭代器方法之外)引发异常,则将执行迭代器方法中的 finally 块。
技术实现
以下代码从迭代器方法返回 IEnumerable<string>,然后遍历其元素。
IEnumerable<string> elements = MyIteratorMethod();
foreach (string element in elements)
{
…
}
调用 MyIteratorMethod 并不执行该方法的主体。相反,该调用会将 IEnumerable<string> 返回到 elements 变量中。
在 foreach 循环迭代时,将为 elements 调用 MoveNext 方法。此调用将执行 MyIteratorMethod 的主体,直至到达下一个 yield return 语句。 yield return 语句返回的表达式不仅决定了循环体使用的 element 变量值,还决定了元素的 Current 属性(它是 IEnumerable<string>)。
在 foreach 循环的每个后续迭代中,迭代器主体的执行将从它暂停的位置继续,直至到达 yield return 语句后才会停止。在到达迭代器方法的结尾或 yield break 语句时,foreach 循环便已完成。
下面的示例包含一个位于 for 循环内的 yield return 语句。 Process 中的 foreach 语句体的每次迭代都会创建对 Power 迭代器函数的调用。对迭代器函数的每个调用将继续到 yield return 语句的下一次执行(在 for 循环的下一次迭代期间发生)。
迭代器方法的返回类型是 IEnumerable(一种迭代器接口类型)。当调用迭代器方法时,它将返回一个包含数字幂的可枚举对象。
public class PowersOf2
{
static void Main()
{
// Display powers of 2 up to the exponent of 8:
foreach (int i in Power(2, 8))
{
Console.Write("{0} ", i);
}
}
public static System.Collections.Generic.IEnumerable<int> Power(int number, int exponent)
{
int result = 1;
for (int i = 0; i < exponent; i++)
{
result = result * number;
yield return result;
}
}
// Output: 2 4 8 16 32 64 128 256
}
下面的示例演示一个作为迭代器的 get 访问器。在该示例中,每个 yield return 语句返回一个用户定义的类的实例。
public static class GalaxyClass
{
public static void ShowGalaxies()
{
var theGalaxies = new Galaxies();
foreach (Galaxy theGalaxy in theGalaxies.NextGalaxy)
{
Debug.WriteLine(theGalaxy.Name + " " + theGalaxy.MegaLightYears.ToString());
}
}
public class Galaxies
{
public System.Collections.Generic.IEnumerable<Galaxy> NextGalaxy
{
get
{
yield return new Galaxy { Name = "Tadpole", MegaLightYears = 400 };
yield return new Galaxy { Name = "Pinwheel", MegaLightYears = 25 };
yield return new Galaxy { Name = "Milky Way", MegaLightYears = 0 };
yield return new Galaxy { Name = "Andromeda", MegaLightYears = 3 };
}
}
}
public class Galaxy
{
public String Name { get; set; }
public int MegaLightYears { get; set; }
}
}
C# 语言规范
有关详细信息,请参阅 C# 语言规范。该语言规范是 C# 语法和用法的权威资料。