yield (C# Reference)
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. 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.
The following example shows the two forms of the yield
statement.
yield return <expression>;
yield break;
Remarks
You use a yield return
statement to return each element one at a time.
The sequence returned from an iterator method can be consumed by using a foreach statement or LINQ query. Each iteration of the foreach
loop calls the iterator method. 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.
When the iterator returns an System.Collections.Generic.IAsyncEnumerable<T>, that sequence can be consumed asynchronously using an await foreach statement. The iteration of the loop is analogous to the foreach
statement. The difference is that each iteration may be suspended for an asynchronous operation before returning the expression for the next element.
You can use a yield break
statement to end the iteration.
For more information about iterators, see Iterators.
Iterator methods and get accessors
The declaration of an iterator must meet the following requirements:
- The return type must be one of the following types:
- The declaration can't have any in, ref, or out parameters.
The yield
type of an iterator that returns IEnumerable or IEnumerator is object
. 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.
You can't include a yield return
or yield break
statement in:
- Lambda expressions and anonymous methods.
- Methods that contain unsafe blocks. For more information, see unsafe.
Exception handling
A yield return
statement can't be located in a try-catch block. A yield return
statement can be located in the try block of a try-finally statement.
A yield break
statement can be located in a try block or a catch block but not a finally block.
If the foreach
or await foreach
body (outside of the iterator method) throws an exception, a finally
block in the iterator method is executed.
Technical implementation
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)
{
...
}
The call to MyIteratorMethod
doesn't execute the body of the method. Instead the call returns an IEnumerable<string>
into the elements
variable.
On an iteration of the foreach
loop, the MoveNext method is called for elements
. This call executes the body of MyIteratorMethod
until the next yield return
statement is reached. 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>
.
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. The foreach
loop completes when the end of the iterator method or a yield break
statement is reached.
The following code returns an IAsyncEnumerable<string>
from an iterator method and then iterates through its elements.
IAsyncEnumerable<string> elements = MyAsyncIteratorMethod();
await foreach (string element in elements)
{
// ...
}
On an iteration of the await foreach
loop, the IAsyncEnumerator<T>.MoveNextAsync method is called for elements
. The System.Threading.Tasks.ValueTask<TResult> return by MoveNext
completes when the next yield return
is reached.
On each subsequent iteration of the await foreach
loop, the execution of the iterator body continues from where it left off, again stopping when it reaches a yield return
statement. The await foreach
loop completes when the end of the iterator method or a yield break
statement is reached.
Examples
The following example has a yield return
statement that's inside a for
loop. Each iteration of the foreach
statement body in the Main
method creates a call to the Power
iterator function. 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.
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
}
The following example demonstrates a get
accessor that is an iterator. 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# language specification
For more information, see the C# Language Specification. The language specification is the definitive source for C# syntax and usage.
See also
Feedback
Submit and view feedback for