yield(C# 参考)yield (C# Reference)

如果你在语句中使用 yield 上下文关键字,则意味着它在其中出现的方法、运算符或 get 访问器是迭代器。When you use the yield contextual keyword in a statement, you indicate that the method, operator, or get accessor in which it appears is an iterator. 通过使用 yield 定义迭代器,可在实现自定义集合类型的 IEnumerator<T>IEnumerable 模式时无需其他显式类(保留枚举状态的类,有关示例,请参阅 IEnumerator)。Using yield to define an iterator removes the need for an explicit extra class (the class that holds the state for an enumeration, see IEnumerator<T> for an example) when you implement the IEnumerable and IEnumerator pattern for a custom collection type.

下面的示例演示了 yield 语句的两种形式。The following example shows the two forms of the yield statement.

yield return <expression>;  
yield break;  

备注Remarks

使用 yield return 语句可一次返回一个元素。You use a yield return statement to return each element one at a time.

通过 foreach 语句或 LINQ 查询来使用迭代器方法。You consume an iterator method by using a foreach statement or LINQ query. foreach 循环的每次迭代都会调用迭代器方法。Each iteration of the foreach loop calls the iterator method. 迭代器方法运行到 yield return 语句时,会返回一个 expression,并保留当前在代码中的位置。When a yield return statement is reached in the iterator method, expression is returned, and the current location in code is retained. 下次调用迭代器函数时,将从该位置重新开始执行。Execution is restarted from that location the next time that the iterator function is called.

可以使用 yield break 语句来终止迭代。You can use a yield break statement to end the iteration.

有关迭代器的详细信息,请参阅迭代器For more information about iterators, see Iterators.

迭代器方法和 get 访问器Iterator Methods and get Accessors

迭代器的声明必须满足以下要求:The declaration of an iterator must meet the following requirements:

返回 yieldIEnumerable 的迭代器的 IEnumerator 类型为 objectThe yield type of an iterator that returns IEnumerable or IEnumerator is object. 如果迭代器返回 IEnumerable<T>IEnumerator<T>,则必须将 yield return 语句中的表达式类型隐式转换为泛型类型参数。If the iterator returns IEnumerable<T> or IEnumerator<T>, there must be an implicit conversion from the type of the expression in the yield return statement to the generic type parameter .

你不能在具有以下特点的方法中包含 yield returnyield break 语句:You can't include a yield return or yield break statement in methods that have the following characteristics:

  • 匿名方法。Anonymous methods. 有关详细信息,请参阅匿名方法For more information, see Anonymous Methods.

  • 包含不安全的块的方法。Methods that contain unsafe blocks. 有关详细信息,请参阅 unsafeFor more information, see unsafe.

异常处理Exception Handling

不能将 yield return 语句置于 try-catch 块中。A yield return statement can't be located in a try-catch block. 可将 yield return 语句置于 try-finally 语句的 try 块中。A yield return statement can be located in the try block of a try-finally statement.

可将 yield break 语句置于 try 块或 catch 块中,但不能将其置于 finally 块中。A yield break statement can be located in a try block or a catch block but not a finally block.

如果 foreach 主体(在迭代器方法之外)引发异常,则将执行迭代器方法中的 finally 块。If the foreach body (outside of the iterator method) throws an exception, a finally block in the iterator method is executed.

技术实现Technical Implementation

以下代码从迭代器方法返回 IEnumerable<string>,然后遍历其元素。The following code returns an IEnumerable<string> from an iterator method and then iterates through its elements.

IEnumerable<string> elements = MyIteratorMethod();  
foreach (string element in elements)  
{  
   ...  
}  

调用 MyIteratorMethod 并不执行该方法的主体。The call to MyIteratorMethod doesn't execute the body of the method. 相反,该调用会将 IEnumerable<string> 返回到 elements 变量中。Instead the call returns an IEnumerable<string> into the elements variable.

foreach 循环迭代时,将为 MoveNext 调用 elements 方法。On an iteration of the foreach loop, the MoveNext method is called for elements. 此调用将执行 MyIteratorMethod 的主体,直至到达下一个 yield return 语句。This call executes the body of MyIteratorMethod until the next yield return statement is reached. yield return 语句返回的表达式不仅决定了循环体使用的 element 变量值,还决定了 elementsCurrent 属性(它是 IEnumerable<string>)。The expression returned by the yield return statement determines not only the value of the element variable for consumption by the loop body but also the Current property of elements, which is an IEnumerable<string>.

foreach 循环的每个后续迭代中,迭代器主体的执行将从它暂停的位置继续,直至到达 yield return 语句后才会停止。On each subsequent iteration of the foreach loop, the execution of the iterator body continues from where it left off, again stopping when it reaches a yield return statement. 在到达迭代器方法的结尾或 foreach 语句时,yield break 循环便已完成。The foreach loop completes when the end of the iterator method or a yield break statement is reached.

示例Example

下面的示例包含一个位于 yield return 循环内的 for 语句。The following example has a yield return statement that's inside a for loop. Main 方法中的 foreach 语句体的每次迭代都会创建对 Power 迭代器函数的调用。Each iteration of the foreach statement body in the Main method creates a call to the Power iterator function. 对迭代器函数的每个调用将继续到 yield return 语句的下一次执行(在 for 循环的下一次迭代期间发生)。Each call to the iterator function proceeds to the next execution of the yield return statement, which occurs during the next iteration of the for loop.

迭代器方法的返回类型是 IEnumerable(一种迭代器接口类型)。The return type of the iterator method is IEnumerable, which is an iterator interface type. 当调用迭代器方法时,它将返回一个包含数字幂的可枚举对象。When the iterator method is called, it returns an enumerable object that contains the powers of a number.

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
}

示例Example

下面的示例演示一个作为迭代器的 get 访问器。The following example demonstrates a get accessor that is an iterator. 在该示例中,每个 yield return 语句返回一个用户定义的类的实例。In the example, each yield return statement returns an instance of a user-defined class.

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# Language Specification

有关详细信息,请参阅 C# 语言规范For more information, see the C# Language Specification. 该语言规范是 C# 语法和用法的权威资料。The language specification is the definitive source for C# syntax and usage.

请参阅See Also