C# Tip: use yield return to return one item at the time

0
104

to me, yield return Has always been one of the hardest things to understand.

Now that I’ve understood this (not thoroughly, but enough to explain it), it’s my turn to share my learning.

So what yes yield return You mean? How does this relate to item collections?

Using lists

Suppose you return a collection of items and you need to repeat them.

A first approach can be to create a list with all the items, return it to the caller and iterate the collection:

IEnumerable<int> WithList()

    List<int> items = new List<int>();

    for (int i = 0; i < 10; i++)
    
        Console.WriteLine($"Added item i");
        items.Add(i);
    

    return items;


void Main()

    var items = WithList();

    foreach (var i in items)
    
        Console.WriteLine($"This is Mambo number i");
    

This section creates the entire collection and then prints the entries within this list. In the console, you will see this text:

Added item 0
Added item 1
Added item 2
Added item 3
Added item 4
Added item 5
Added item 6
Added item 7
Added item 8
Added item 9
This is Mambo number 0
This is Mambo number 1
This is Mambo number 2
This is Mambo number 3
This is Mambo number 4
This is Mambo number 5
This is Mambo number 6
This is Mambo number 7
This is Mambo number 8
This is Mambo number 9

This means that if you need to run on a collection with a million items, you will first create all the items, and then perform actions on each of them. This approach has two main drawbacks: it is slow (especially if you only need to work with a subset of these items), and takes up a lot of memory.

With yield

We can use another approach: Use yield return Keywords:

IEnumerable<int> WithYield()

    for (int i = 0; i < 10; i++)
    
        Console.WriteLine($"Returning item i");

        yield return i;
    


void Main()

    var items = WithYield();

    foreach (var i in items)
    
        Console.WriteLine($"This is Mambo number i");
    

In this method, the order of the messages is changed:

Returning item 0
This is Mambo number 0
Returning item 1
This is Mambo number 1
Returning item 2
This is Mambo number 2
Returning item 3
This is Mambo number 3
Returning item 4
This is Mambo number 4
Returning item 5
This is Mambo number 5
Returning item 6
This is Mambo number 6
Returning item 7
This is Mambo number 7
Returning item 8
This is Mambo number 8
Returning item 9
This is Mambo number 9

Therefore, instead of creating the entire list, we create one item at a time, and only when necessary.

Yield benefits

As I said before, there are some benefits with yield: The app has higher performance when it comes to both execution time and memory usage.

It’s like an automatic iterator: every time you get a result, the iterator advances to the next item.

Just a note: yield Works only for recurring methods IAsyncEnumerable<T>, IEnumerable<T>, IEnumerable, IEnumerator<T>, Or IEnumerator.

You can not use it in a method that returns, for example, List<T>, Because as the error message says,

X’s body can not be an iterator block because List<int> Is not a type of iterator interface


Real use case

If you use NUnit As a test package, you have probably already used this keyword.

In particular, when using TestCaseSource Feature, you specify the name of the department that issues the test cases.

public class MyTestClass

    [TestCaseSource(typeof(DivideCases))]
    public void DivideTest(int n, int d, int q)
    
        Assert.AreEqual(q, n / d);
    


class DivideCases : IEnumerable

    public IEnumerator GetEnumerator()
    
        yield return new object[]  12, 3, 4 ;
        yield return new object[]  12, 2, 6 ;
        yield return new object[]  12, 4, 3 ;
    

When performing the tests, the iterator returns a test case at a time, without creating a complete list of test cases.

The previous section was taken directly from the NUnit documentation for TestCaseSource attribute, Which you can find here.

Finishing

Yes, yield Is a rather difficult keyword to understand.

For further reading, go to The official documents.

Another good resource is “C # – Use Yield Return to Minimize Memory Usage” By Macolite. You should definitely check it out!

And if you like, check out the conversation I had about this keyword On Twitter.

Happy coding!

.

Source

LEAVE A REPLY

Please enter your comment!
Please enter your name here