C# yield - using yield keyword in C# language (2024)

last modified February 1, 2024

In this article we show how to use yield keyword in C# language.

The yield keyword

The yield keyword is use to do custom stateful iteration over acollection. The yield keyword tells the compiler that the method in which itappears is an iterator block.

yield return <expression>;yield break;

The yield return statement returns one element at a time. Thereturn type of yield keyword is either IEnumerable orIEnumerator. The yield break statement is used to endthe iteration.

We can consume the iterator method that contains a yield return statement eitherby using foreach loop or LINQ query. Each iteration of the loop calls theiterator method. When a yield return statement is reached in the iteratormethod, the expression is returned, and the the current location in code isretained. Execution is restarted from that location the next time that theiterator function is called.

Two important aspects of using yield are:

  • lazy evaluation
  • deferred execution

C# yield example

In the first examples, we work with Fibonacci sequence.

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...

The Fibonacci sequence is the series of numbers, where the next number is foundby adding up the two numbers before it.

Program.cs

var data = Fibonacci(10);foreach (int e in data){ Console.WriteLine(e);}IEnumerable<int> Fibonacci(int n){ var vals = new List<int>(); for (int i = 0, n1 = 0, n2 = 1; i < n; i++) { int fib = n1 + n2; n1 = n2; vals.Add(fib); n2 = fib; } return vals;}

Here, we compute the sequence without the yield keyword. We printthe first ten values of the sequence.

var vals = new List<int>();

This implementation requires a new list. Imagine that we worked hundreds ofmillions of values. This would significantly slow our computation and wouldrequire huge amount of memory.

$ dotnet run 123581321345589

Next, we use the yield keyword to generate the Fibonacci sequence.

Program.cs

foreach (int fib in Fibonacci(10)){ Console.WriteLine(fib);}IEnumerable<int> Fibonacci(int n){ for (int i = 0, n1 = 0, n2 = 1; i < n; i++) { yield return n1; int temp = n1 + n2; n1 = n2; n2 = temp; }}

This implementation starts producing numbers before reaching the specified endof the sequence.

for (int i = 0, n1 = 0, n2 = 1; i < n; i++){ yield return n1; int temp = n1 + n2; n1 = n2; n2 = temp;}

The yield return returns the currently computed value to theabove foreach statement. The n1, n2,temp values are remembered; C# creates a class behind the scenesto keep these values.

We can have multiple yields statements.

Program.cs

int n = 10;IEnumerable<string> res = FibSeq().TakeWhile(f => f.n <= n).Select(f => $"{f.fib}");Console.WriteLine(string.Join(" ", res));IEnumerable<(int n, int fib)> FibSeq(){ yield return (0, 0); yield return (1, 1); var (x, y, n) = (1, 0, 0); while (x < int.MaxValue - y) { (x, y, n) = (x + y, x, n + 1); yield return (n, x); }}

In the example, we calculate the Fibonacci sequence with the help of tuples.

IEnumerable<string> res = FibSeq().TakeWhile(f => f.n <= n).Select(f => $"{f.fib}");

We consume the Fibonacci sequence with the LINQ's TakeWhile method.

Console.WriteLine(string.Join(" ", res));

The sequence of strings is joined.

IEnumerable<(int n, int fib)> FibSeq(){ yield return (0, 0); yield return (1, 1); var (x, y, n) = (1, 0, 0); while (x < int.MaxValue - y) { (x, y, n) = (x + y, x, n + 1); yield return (n, x); }}

The FibSeq method returns a sequence of tuple values. Each tuplecontains the n value, up to which we generate the sequence andthe current Fibonacci value fib.

yield return (0, 0);yield return (1, 1);

The first two tuples are returned with yield return.

var (x, y, n) = (1, 0, 0);while (x < int.MaxValue - y){ (x, y, n) = (x + y, x, n + 1); yield return (n, x);}

The rest of the sequence is calculated with a while loop. The sequence goesup to int.MaxValue.

C# yield running total

The yield stores state; the next program demonstrates this.

Program.cs

List<int> vals = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];foreach (int e in RunningTotal()){ Console.WriteLine(e);}IEnumerable<int> RunningTotal(){ int runningTotal = 0; foreach (int val in vals) { runningTotal += val; yield return runningTotal; }}

The example calculates the running total for a list of integers. TherunningTotal is stored when the control goes between the iteratorand the consumer of the iterator.

$ dotnet run 13610152128364555

C# yield partition example

In the next example, we compare the efficiency of two approaches to partitioninga huge list.

Program.cs

using System.Collections.ObjectModel;var vals = Enumerable.Range(1, 100_000_000);var option = int.Parse(args[0]);IEnumerable<IEnumerable<int>> result;if (option == 1){ result = Partition1(vals, 5);} else { result = Partition2(vals, 5);}foreach (var part in result){ // Console.WriteLine(string.Join(", ", part));}Console.WriteLine(string.Join(", ", result.First()));Console.WriteLine(string.Join(", ", result.Last()));Console.WriteLine("-------------------");Console.WriteLine("Finished");IEnumerable<IEnumerable<int>> Partition1(IEnumerable<int> source, int size){ int[] array = null; int count = 0; var data = new List<IEnumerable<int>>(); foreach (int item in source) { if (array == null) { array = new int[size]; } array[count] = item; count++; if (count == size) { data.Add(new ReadOnlyCollection<int>(array)); array = null; count = 0; } } if (array != null) { Array.Resize(ref array, count); data.Add(new ReadOnlyCollection<int>(array)); } return data;}IEnumerable<IEnumerable<int>> Partition2(IEnumerable<int> source, int size){ int[] array = null; int count = 0; foreach (int item in source) { if (array == null) { array = new int[size]; } array[count] = item; count++; if (count == size) { yield return new ReadOnlyCollection<int>(array); array = null; count = 0; } } if (array != null) { Array.Resize(ref array, count); yield return new ReadOnlyCollection<int>(array); }}

We have a sequence of a hundred million vallues. We partition them into groupsof five values with and without the yield keyword and compare theefficiency.

var vals = Enumerable.Range(1, 100_000_000);

A sequence of one hundred million values is generated withEnumerable.Range.

var option = int.Parse(args[0]);IEnumerable<IEnumerable<int>> result;if (option == 1){ result = Partition1(vals, 5);} else { result = Partition2(vals, 5);}

The program is run with a parameter. The option 1 invokesPartition1 function. The yield keyword is used inPartition2 and is invoked with option other than 1.

var data = new List<IEnumerable<int>>();...return data;

The Partition1 function builds a list with values partitionedinside. For one hundred million values, this requires a significant chunk ofmemory. Also, if there is not enough free memory, the operating system startsswapping the memory to disk which slows down the computation.

if (array != null){ Array.Resize(ref array, count); yield return new ReadOnlyCollection<int>(array);}

In Partition2, we return one partitioned collection at a time. Wedon't wait for the whole process to finish. This approach requires less memory.

$ /usr/bin/time -f "%M KB %e s" bin/Release/net5.0/Partition 11, 2, 3, 4, 599999996, 99999997, 99999998, 99999999, 100000000-------------------Finished1696712 KB 6.38 s$ /usr/bin/time -f "%M KB %e s" bin/Release/net5.0/Partition 21, 2, 3, 4, 599999996, 99999997, 99999998, 99999999, 100000000-------------------Finished30388 KB 2.99 s

We use the time command to compare the two functions. In our caseit was 1.7 GB vs 30 MB.

Source

yield statement - language reference

In this article we have worked with C# yield keyword.

Author

My name is Jan Bodnar and I am a passionate programmer with many years ofprogramming experience. I have been writing programming articles since 2007. Sofar, I have written over 1400 articles and 8 e-books. I have over eight years ofexperience in teaching programming.

List all C# tutorials.

C# yield - using yield keyword in C# language (2024)

FAQs

When to use yield keyword in C#? ›

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 .

Is yield break necessary in C#? ›

No this is not necessary. It will work: public static IEnumerable<int> GetDiff(int start, int end) { while (start < end) { yield return start; start++; } // yield break; - It is not necessary. It is like `return` which does not return a value. }

Is yield return more efficient? ›

Conclusion. yield return is a powerful feature for creating efficient and readable C# code. It's particularly useful for handling large data sets and streams, making your applications more memory-efficient and responsive.

What is the use of the yield keyword? ›

The yield keyword pauses generator function execution and the value of the expression following the yield keyword is returned to the generator's caller. It can be thought of as a generator-based version of the return keyword. yield can only be used directly within the generator function that contains it.

Why should I use yield? ›

The advantages of using yield keywords instead of return are that the values returned by yield statement are stored as local variables states, which allows control over memory overhead allocation. Also, each time, the execution does not start from the beginning, since the previous state is retained.

What is the difference between LINQ and yield? ›

LINQ's fluent syntax and Select's succinct projection make queries easy to read and maintain. On the other hand, Yield Return's ability to generate data in a readable, procedural manner promotes clarity in code.

What is the difference between yield return and return in C#? ›

An iterator is a method that uses the yield return keywords. yield return is different from a normal return statement because, while it does return a value from the function, it doesn't “close the book” on that function.

What is the difference between enumerator and iterator in C#? ›

Iterating means repeating some steps, while enumerating means going through all values in a collection of values. So enumerating usually requires some form of iteration. In that way, enumerating is a special case of iterating where the step is getting a value from a collection.

What is the use of IEnumerable in C#? ›

Benefits of using IEnumerable:

It enables the usage of the foreach loop, which streamlines iteration and increases readability of the code, making it simpler to comprehend and maintain. Deferred Execution: IEnumerable allows for deferred execution, which prevents immediate iteration over the collection.

What is yield good for? ›

It's commonly used to refer to interest payments an investor receives on a bond or dividend payments on a stock. Yield is often expressed as a percentage, based on either the investment's market value or purchase price. For example, let's say bond A has a $1,000 face value and pays a semiannual coupon of $10.

Can we use yield and return together? ›

In conclusion , the combination of yield and return within the same function allows developers to create versatile and powerful code structures in Python.

Why is it important to yield? ›

Yield signs play a crucial role in preventing confusion and potential accidents. When you encounter a yield sign, it's essential to slow down, check for oncoming traffic, and yield to vehicles that have the right-of-way. This simple action contributes to a safer road environment for everyone.

What is the use of task yield in C#? ›

You can use await Task. Yield(); in an asynchronous method to force the method to complete asynchronously. If there is a current synchronization context (SynchronizationContext object), this will post the remainder of the method's execution back to that context.

What is the difference between yield and return keyword? ›

Yield is generally used to convert a regular Python function into a generator. Return is generally used for the end of the execution and “returns” the result to the caller statement. It replace the return of a function to suspend its execution without destroying local variables.

What is the difference between return and yield return in C#? ›

yield return is different from a normal return statement because, while it does return a value from the function, it doesn't “close the book” on that function.

What is the difference between the await keyword and the yield keyword? ›

The main difference is that generators use the yield keyword to pause and resume the execution of a function, whereas async/await uses the await keyword to pause and resume the execution of a function.

References

Top Articles
Latest Posts
Article information

Author: Jeremiah Abshire

Last Updated:

Views: 6107

Rating: 4.3 / 5 (74 voted)

Reviews: 89% of readers found this page helpful

Author information

Name: Jeremiah Abshire

Birthday: 1993-09-14

Address: Apt. 425 92748 Jannie Centers, Port Nikitaville, VT 82110

Phone: +8096210939894

Job: Lead Healthcare Manager

Hobby: Watching movies, Watching movies, Knapping, LARPing, Coffee roasting, Lacemaking, Gaming

Introduction: My name is Jeremiah Abshire, I am a outstanding, kind, clever, hilarious, curious, hilarious, outstanding person who loves writing and wants to share my knowledge and understanding with you.