Table of Contents (top down ↓)
What is IEnumerable
IEnumerable interface is implemented by collections and arrays. It signals the ability to provide its items one by one like a stream; it supports a simple iteration by using a loop.
// get IEnumerable var ie = new int[] { 3, 5, 6 }; // get IEnumerator var iterator = ie.GetEnumerator(); while (iterator.MoveNext()) { Console.WriteLine($"{iterator.Current}"); } /* output 3 5 6 */
IEnumerable interface implements a method called GetEnumerator that provides an enumerator for the collection. This enumerator is another interface that provides the next element through the MoveNext method that returns false when it reaches past the end of the collection. It provides the current element through a property called Current.
A while keeps moving the iterator. Each item is available in the Current property and displayed using console writeline.
This code is a roundabout way of looping through the elements. But things are not that difficult in real practice. A for-each loop simplifies this iteration. The code can be simplified a lot as you are seeing here.
// a foreach loop is simpler // does the same thing var ie = new int[] { 3, 5, 6 }; foreach(var item in ie) { Console.WriteLine($"{item}"); }
A for-each loop directly provides the item. You must already be familiar with this code. It hides a lot of code behind the scenes.
Video Explanation (see it happen!)
Please watch the following youtube video:
What is yield keyword?
An IEnumerable can be obtained from a function by using the yield keyword.
Suppose we have to provide integers from a function as shown here. This function returns an IEnumerable. But there are multiple yield statements each of which returns an int. This code might be confusing at first. But it is a C# feature that successively executes each yield return statement after each call to the getNumbers function. Notice that all numbers are not returned in one step. Multiple calls are needed to stream the numbers. This technique makes optimal use of both the processor and memory.
Let me explain how the steps take place. Execution proceeds till the first yield statement. The data is returned to the caller and execution is suspended. The execution resumes at the next yield statement when the next iteration takes place. This sequence of suspend-resume siphons out the numbers step-by-step. It optimizes the use of processor and memory.
// program.cs file IEnumerable<int> getNumbers() { yield return 0; yield return 3; yield return -9; yield return 2; yield return 45; } // foreach to iterate over IEnumerable foreach (var n in getNumbers()) { Console.WriteLine(n); }
A for-each loop has been used to obtain the numbers one by one. The series is, step-by-step, printed on the console.
Printing a Fibonacci Series
The yield statement can be used to write a very readable program for printing a fibonacci series.
Let us write a program to print the first 20 fibonacci numbers.
// program.cs file // prints a fibonacci series IEnumerable<int> getNumbers() { int first = -1; int second = 1; for (int i = 0; i < 20; i++) { int sum = first + second; first = second; second = sum; yield return sum; } } // print the sequence foreach (var n in getNumbers()) { Console.WriteLine(n); }
We have to write a function that returns an IEnumerable of int numbers.
We have created two variables, first and second to hold consequetive numbers.
A for-loop is required to return 20 numbers one-by-one.
The sum of first and second is done. After that the values of first and second are shifted as per the fibonacci series.
Finally, the yield return statement returns the fibonacci number.
Notice that the yield keyword makes the whole process readable, intuitive and memory efficient at the same time.
A for-each loop makes the iteration calls and prints all the 20 numbers one-by-one. Thankyou!
Similar Posts
This Blog Post/Article "(C# Language) LINQ - IEnumerable, yield and Enumerator" by Parveen is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.