What does "yield break;" do in C#?

It specifies that an iterator has come to an end. You can think of yield break as a return statement which does not return a value.

For example, if you define a function as an iterator, the body of the function may look like this:

for (int i = 0; i < 5; i++)
{
    yield return i;
}

Console.Out.WriteLine("You will see me");

Note that after the loop has completed all its cycles, the last line gets executed and you will see the message in your console app.

Or like this with yield break:

int i = 0;
while (true)
{
    if (i < 5)
    {
        yield return i;
    }
    else
    {
        // note that i++ will not be executed after this
        yield break;
    }
    i++;
}

Console.Out.WriteLine("Won't see me");

In this case the last statement is never executed because we left the function early.


Ends an iterator block (e.g. says there are no more elements in the IEnumerable).


Tells the iterator that it's reached the end.

As an example:

public interface INode
{
    IEnumerable<Node> GetChildren();
}

public class NodeWithTenChildren : INode
{
    private Node[] m_children = new Node[10];

    public IEnumerable<Node> GetChildren()
    {
        for( int n = 0; n < 10; ++n )
        {
            yield return m_children[ n ];
        }
    }
}

public class NodeWithNoChildren : INode
{
    public IEnumerable<Node> GetChildren()
    {
        yield break;
    }
}

yield basically makes an IEnumerable<T> method behave similarly to a cooperatively (as opposed to preemptively) scheduled thread.

yield return is like a thread calling a "schedule" or "sleep" function to give up control of the CPU. Just like a thread, the IEnumerable<T> method regains controls at the point immediately afterward, with all local variables having the same values as they had before control was given up.

yield break is like a thread reaching the end of its function and terminating.

People talk about a "state machine", but a state machine is all a "thread" really is. A thread has some state (I.e. values of local variables), and each time it is scheduled it takes some action(s) in order to reach a new state. The key point about yield is that, unlike the operating system threads we're used to, the code that uses it is frozen in time until the iteration is manually advanced or terminated.


The yield break statement causes the enumeration to stop. In effect, yield break completes the enumeration without returning any additional items.

Consider that there are actually two ways that an iterator method could stop iterating. In one case, the logic of the method could naturally exit the method after returning all the items. Here is an example:

IEnumerable<uint> FindPrimes(uint startAt, uint maxCount)
{
    for (var i = 0UL; i < maxCount; i++)
    {
        startAt = NextPrime(startAt);
        yield return startAt;
    }

    Debug.WriteLine("All the primes were found.");
}

In the above example, the iterator method will naturally stop executing once maxCount primes have been found.

The yield break statement is another way for the iterator to cease enumerating. It is a way to break out of the enumeration early. Here is the same method as above. This time, the method has a limit on the amount of time that the method can execute.

IEnumerable<uint> FindPrimes(uint startAt, uint maxCount, int maxMinutes)
{
    var sw = System.Diagnostics.Stopwatch.StartNew();
    for (var i = 0UL; i < maxCount; i++)
    {
        startAt = NextPrime(startAt);
        yield return startAt;

        if (sw.Elapsed.TotalMinutes > maxMinutes)
            yield break;
    }

    Debug.WriteLine("All the primes were found.");
}

Notice the call to yield break. In effect, it is exiting the enumeration early.

Notice too that the yield break works differently than just a plain break. In the above example, yield break exits the method without making the call to Debug.WriteLine(..).