# C# Yield Return Statement

> In this week's newsletter I want to talk about the yield keyword in C#. The yield keyword tells the compiler that the method is an iterator block, which returns a lazily evaluated IEnumerable. Let's see how we can start using it.

Published: 2023-01-21. Author: Milan Jovanović.

Canonical: https://milanjovanovic.tech/blog/csharp-yield-return-statement

In this week's newsletter I want to talk about the `yield` keyword in **C#**.
I think it's a powerful **C#** feature and I wanted to highlight the benefits.

The `yield` keyword tells the compiler that the method in which it appears
is an **iterator block**. An iterator block, or method, returns an `IEnumerable`
as the result. And the `yield` keyword is used to return the values for the
`IEnumerable`.

An interesting thing aboug `IEnumerable` is that it is lazily evaluted.
Calling a method with an iterator block doesn't run any code. It's only
when the `IEnumerable` is iterated over, or enumerated, that we get
the actual values. I'll talk about this more later.

Let's see how we can start using the `yield` keyword!

## How To Use The Yield Keyword

The `yield` keyword on it's own doesn't do anything, you have to combine
it with the `return` or `break` statement:

- `yield return` - provides the next value of the iterator
- `yield-break` - signals the end of iteration

In every project I worked on, there's a piece of code similar to the
following. You create a list to hold the results, add elements to the
list, and return the list in the end.

```csharp
var engineers = GetSoftwareEngineers();

public IEnumerable<SoftwareEngineer> GetSoftwareEngineers()
{
    var result = new List<SoftwareEngineer>();

    for(var i = 0; i < 10; i++)
    {
        result.Add(new SoftwareEngineer
        {
            Id = i
        });
    }

    return result;
}
```

You can simplify the method using the `yield return` statement, and
completely remove the intermediate list required to hold the results.

```csharp
var engineers = GetSoftwareEngineers();

public IEnumerable<SoftwareEngineer> GetSoftwareEngineers()
{
    for(var i = 0; i < 10; i++)
    {
        yield return new SoftwareEngineer
        {
            Id = i
        };
    }
}
```

However, it's important to note these two implementation are fundamentally
different from each other. In the first example, the entire list is
populated and materialized. In the second example, the `IEnumerable`
returned will not be materialized and you have to either iterate over
it inside a `foreach` loop or call `ToList()`.

## Stopping Iteration With Yield Break

You can use the `yield break` statement to stop iteration and exit
the iterator block. Typically you would do this when a certain
condition is met, or you only want to return a specific set of values
from the iterator block.

Here's an example where this would be useful:

```csharp
Console.WriteLine(string.Join(", ", TakeWhilePositive(new[] { 1, 2, -3, 4 })));
// Output: 1, 2

public IEnumerable<int> TakeWhilePositive(IEnumerable<int> numbers)
{
    foreach(int num in numbers)
    {
        if (num > 0)
        {
            yield return num;
        }
        else
        {
            yield break;
        }
    }
}
```

## Working With IAsyncEnumerable

In **C# 8** we got the `IAsyncEnumerable` type which allows us to
iterate over a collection asynchronously with the `yield` statement.

For example, this can be useful when you want to call a thid-party
API multiple times to fetch some data. A common situation is when
you get a list of users from the database, and then have to call
an external storage service to get profile picture information.

Without `IAsyncEnumerable` you would have to do something like this:

```csharp
public async Task<IEnumerable<User>> GetUsersAsync()
{
    var users = await GetUsersFromDbAsync();

    foreach(var user in users)
    {
        user.ProfileImage = await GetProfileImageAsync(user.Id);
    }

    return users;
}

// And you would call the method like this.
var users = await GetUsersAsync();

foreach(var user in users)
{
    Console.WriteLine(user);
}
```

Now, consider this same example with the use of `IAsyncEnumerable`:

```csharp
public async IAsyncEnumerable<User> GetUsersAsync()
{
    var users = await GetUsersFromDbAsync();

    foreach(var user in users)
    {
        user.ProfileImage = await GetProfileImageAsync(user.Id);

        yield return user;
    }
}

// And you would call the method like this.
await foreach(var user in GetUsersAsync())
{
    Console.WriteLine(user);
}
```

The second implementation will iterate over the users returned from
the database when they are yielded by the `IAsyncEnumerable`.

## When Should I Use Yield?

I've found a few interesting practical applications for the `yield` keyword.
One example is when implementing Domain-Driven Design **value objects**.

Value objects need to support structural equality. They need to implement
a method that returns all of the equality components. Here's an example of
that using the `yield return` statement:

```csharp
public class Address
{
    public string City { get; init; }

    public string Street { get; init; }

    public string Zip { get; init; }

    public string Country { get; init; }

    public IEnumerable<object> GetEqualityComponents()
    {
        yield return City;
        yield return Street;
        yield return Zip;
        yield return Country;
    }
}
```

---

## Frequently asked questions

### What does the yield keyword do in C#?

The yield keyword tells the compiler that the method is an iterator block, which returns an IEnumerable. You combine it with return or break: yield return provides the next value of the iterator, and yield break signals the end of iteration.

### Is IEnumerable lazily evaluated in C#?

Yes. Calling a method with an iterator block does not run any code. You only get the actual values when the IEnumerable is iterated over, for example in a foreach loop or by calling ToList().

### What is the difference between yield return and returning a list?

Returning a list materializes the entire collection before returning it. With yield return there is no intermediate list, and the IEnumerable is not materialized until you enumerate it, so the two implementations behave fundamentally differently.

### When should you use yield break?

Use yield break to stop iteration and exit the iterator block, typically when a certain condition is met or when you only want to return a specific set of values, such as taking numbers from a sequence only while they are positive.

### What is IAsyncEnumerable in C#?

IAsyncEnumerable, introduced in C# 8, lets you iterate over a collection asynchronously with the yield statement and consume it with await foreach. It is useful when producing each element requires an asynchronous call, like fetching profile data for every user.
