How yield return works in c# - c#

I have following piece of code.
public static void main(string []args)
{
var intergers = GetCollection();
foreach(var val in intergers)
{
console.writeline(val);
}
}
public IEnumerable<int> GetCollection()
{
yield return 10;
var obj = new MyClass();
obj.performLargeAction();
yield return 1;
var obj = new MyClass();
obj.perform();
yield return 2;
console.writeline("I am finished now");
}
Now, when I debug the code and see the foreach iteration, then I see that first time method executes till yield return 10 and then control goes back to foreach loop, on next iteration code after yield return 10 and till yield return 1 is executed and in next iteration it executes from line right after yield return 1 and till yield return and in next iteration it
calls console.writeline();
So, with this behavior, I am keen to know does .net pause the execution of the method which is returning IEnumerable and save its location counter or state to the stack and next iteration again pops the location and set it to program counter or location counter and all these thing or
I have read something yield is a c# feature, so this above piece of code is converted to IL and that yield part is replaced with a class called YieldEnumerator which stores state, current and other thing. but still I could not understand its actual functioning. So, I would like to know its internal working form starting to end.

Related

Why does Lazy<T> using ExecutionAndPublication behave differently with yielded IEnumerables?

I had a problem in my code where a Lazy initializer was called more frequently than what I expected. From the documentation, I expected that using LazyThreadSafetyMode.ExecutionAndPublication would ensure my initializer function was only ever called once, for example if accessing numbers.Value after defining:
numbers = new Lazy<IEnumerable<int>>(
() => GetNumbers(),
LazyThreadSafetyMode.ExecutionAndPublication
);
However, what I have found is that if the initialization function yields its results, the initialization function gets called more than once. I presume this has to with yields delayed execution but I only have a fuzzy sense why.
Question:
In the code below, why do the respective initialization functions get executed a different number of times?
void Main()
{
var foo = new foo();
var tasks = new List<Task>();
for (int i = 0; i < 10; ++i) tasks.Add(Task.Run(() => {foreach (var number in foo.Numbers) Debug.WriteLine(number);}));
Task.WaitAll(tasks.ToArray());
tasks.Clear();
for (int i = 0; i < 10; ++i) tasks.Add(Task.Run(() => {foreach (var letter in foo.Letters) Debug.WriteLine(letter);}));
Task.WaitAll(tasks.ToArray());
}
public class foo
{
public IEnumerable<int> Numbers => numbers.Value;
public IEnumerable<char> Letters => letters.Value;
readonly Lazy<IEnumerable<int>> numbers;
readonly Lazy<IEnumerable<char>> letters;
public foo()
{
numbers = new Lazy<IEnumerable<int>>(
() => GetNumbers(),
LazyThreadSafetyMode.ExecutionAndPublication
);
letters = new Lazy<IEnumerable<char>>(
() => GetLetters().ToList(), //ToList enumerates all yielded letters, creating the expected call once behavior
LazyThreadSafetyMode.ExecutionAndPublication
);
}
protected IEnumerable<char> GetLetters()
{
Debug.WriteLine($"{nameof(GetLetters)} Called");
yield return 'a';
yield return 'b';
yield return 'c';
yield break;
}
protected IEnumerable<int> GetNumbers()
{
Debug.WriteLine($"{nameof(GetNumbers)} Called");
yield return 1;
yield return 2;
yield return 3;
yield break;
}
}
I had a problem in my code where a Lazy initializer was called more frequently than what I expected.
No, the initializer of the lazy is called once. The initializer of the lazy is
() => GetNumbers()
and that is called exactly once.
GetNumbers returns an IEnumerable<int> -- a sequence of integers.
When you foreach that sequence, it calls GetEnumerator to get an enumerator, and then calls MoveNext on the enumerator object until MoveNext returns false.
You've said that you want the sequence to be enumerated as:
the first time MoveNext is called, do a writeline and produce 1
the second time MoveNext is called, produce 2
the third time MoveNext is called, produce 3
the fourth time MoveNext is called, produce 4
Every subsequent time MoveNext is called, return false
So every time you enumerate the sequence, that's what happens.
Can you explain what you expected to happen? I am interested to learn why people have false beliefs about computer programs.
Also it is not clear to me why you are using Lazy at all. You would typically use Lazy to avoid expensive work until it is needed, but sequences already defer work until they are enumerated.

Why can't we debug a method with yield return for the following code? [duplicate]

This question already has answers here:
Cannot step into a method returning IEnumerable<T>?
(4 answers)
Closed 7 years ago.
Following is my code:
class Program {
static List<int> MyList;
static void Main(string[] args) {
MyList = new List<int>() { 1,24,56,7};
var sn = FilterWithYield();
}
static IEnumerable<int> FilterWithYield() {
foreach (int i in MyList) {
if (i > 3)
yield return i;
}
}
}
I have a break point in FilterWithYield Method but its not at all hitting the break point. I have one break at the calling point i.e var sn = FilterWithYield(); Control hits this point and shows the result correctly in debugging window. But why isn't the control stopping in the FilterWithYield method?
One more question. I read that yield returns data to the caller..if that is so if changed return type of FilterWithYield method to int it through error.Does the yield key word always need IEnumerable<T> as return type?
You can debug the method. The problem is, the code that you are trying to reach is never executed.
IEnumerable methods with yield return produce code that makes your sequence lazily, as you go through enumeration. However, when you do this
var sn = FilterWithYield();
you prepare to enumerate the sequence, but you do not start enumerating it.
If, on the other hand, you add a foreach loop or call ToList() on the result, your breakpoint would get hit:
foreach (var n in FilterWithYield()) {
Console.WriteLine(n);
}
or
var sn = FilterWithYield().ToList();

Code after yield return is executed

Consider the following example:
class YieldTest
{
static void Main(string[] args)
{
var res = Create(new string[] { "1 12 123", "1234", "12345" });
}
static IEnumerable<int> Create(IEnumerable<string> strings)
{
foreach(string s in strings)
{
yield return s.Length;
if(s.Contains(' '))
{
string[] tokens = s.Split(' ');
foreach(string t in tokens)
{
yield return t.Length;
}
}
}
}
}
The call to Create returns {8, 1, 2, 3, 4, 5}.
What really confuses me is that the code after the yield return statement is executed.
(Why would they name it yield return and not just yield ??)
The documentation tells us
When a yield return statement is reached in the iterator method,
expression is returned, and the current location in code is retained.
What does that mean? Where does a return occur? What is an iterator method?
It means your code is transformed into a state machine by the compiler.
When you call Create method, you'll get an IEnumerable<T>. You can then call GetEnumerator() on it and obtain an IEnumerator<T>.
Now, every time you call MoveNext on this iterator, your code will execute until it finds the first yield statement (whether it be yield return or yield break).
If it hits a yield return x, MoveNext returns true and the iterator's Current property will be set to x, and the rest of the code will be executed the next time you call MoveNext.
This happens until either there's no more code to run or the code hits a yield break. At that point, MoveNext will return false.
yield return 1;
yield return 2;
yield return 3;
Calling MoveNext on this piece of code will return true the first three times, and at each iteration, Current will be set to 1, 2 and 3.
Edit 2:
Regarding the yield return ?? syntax, from Eric Lippert's Ambiguous Optional Parentheses, Part Three
When they designed C# 2.0 they had this problem:
yield(x);
Does that mean "yield x in an iterator" or "call the yield method with argument x?" By changing it to
yield return(x);
it is now unambiguous; it cannot possibly mean "call the yield method".
The most important part of your quote is:
and the current location in code is retained.
The iterator method does not return in a sense of exiting the method, otherwise you could only enumerate one item. yield return returns one element that is enumerated and then continues to run the code of the iterator method at the spot of the yield return in order to return the next elements when it encounters the next yield return.
An iterator method iterates over a collection and provides the single items by using yield return. These statements allow for a simplified implementation of the IEnumerable interface. In earlier versions of .NET, you had to implement a specific class as the enumerator. As this meant to introduce a lot of boilerplate code for each implementation of IEnumerable, the yield statements were introduced to create an iterator method in a simpler way. The yield return statements in the iterator method provide a signal to the compiler that a new element is to be returned. When building the project, the compiler transfers the iterator method to an implementation of IEnumerable.
An iterator method like this will run until it finds a yield return whenever you fetch a new value from the iterator that it produces. I believe technically it is when you call the MoveNext method of the Enumerator.
When you call MoveNext the next time execution will resume from where it left off in the iterator method and keep going until it gets to the next yield return.
Essentially every call to yield return in your iterator method will yield one of the values in your final enumerable.

Cannot print to console using yield return

In the tests below, I cannot get Console.WriteLine to really print when using yield return.
I'm experimenting with yield return and I understand I have something missing in my understanding of it, but cannot find out what it is. Why aren't the strings printed inside PrintAllYield?
Code:
class Misc1 {
public IEnumerable<string> PrintAllYield(IEnumerable<string> list) {
foreach(string s in list) {
Console.WriteLine(s); // doesn't print
yield return s;
}
}
public void PrintAll(IEnumerable<string> list) {
foreach(string s in list) {
Console.WriteLine(s); // surely prints OK
}
}
}
Test:
[TestFixture]
class MiscTests {
[Test]
public void YieldTest() {
string[] list = new[] { "foo", "bar" };
Misc1 test = new Misc1();
Console.WriteLine("Start PrintAllYield");
test.PrintAllYield(list);
Console.WriteLine("End PrintAllYield");
Console.WriteLine();
Console.WriteLine("Start PrintAll");
test.PrintAll(list);
Console.WriteLine("End PrintAll");
}
}
Output:
Start PrintAllYield
End PrintAllYield
Start PrintAll
foo
bar
End PrintAll
1 passed, 0 failed, 0 skipped, took 0,39 seconds (NUnit 2.5.5).
You have to actually enumerate the returned IEnumerable to see the output:
Console.WriteLine("Start PrintAllYield");
foreach (var blah in test.PrintAllYield(list))
; // Do nothing
Console.WriteLine("End PrintAllYield");
When you use the yield return keyword, the compiler will construct a state machine for you. Its code will only be run when you actually use it to iterate the returned enumerable.
Is there a particular reason you're trying to use yield return to print out a sequence of strings? That's not really the purpose of the feature, which is to simplify the creation of sequence generators, rather than the enumeration of an already generated sequence. foreach is the preferred method for the latter.

Need help understanding C# yield in IEnumerable

i am reading C# 2010 Accelerated. i dont get what is yield
When GetEnumerator is called, the code
in the method that contains the yield
statement is not actually executed at
that point in time. Instead, the
compiler generates an enumerator
class, and that class contains the
yield block code
public IEnumerator<T> GetEnumerator() {
foreach( T item in items ) {
yield return item;
}
}
i also read from Some help understanding “yield”
yield is a lazy producer of data, only
producing another item after the first
has been retrieved, whereas returning
a list will return everything in one
go.
does this mean that each call to GetEnumerator will get 1 item from the collection? so 1st call i get 1st item, 2nd, i get the 2nd and so on ... ?
Best way to think of it is when you first request an item from an IEnumerator (for example in a foreach), it starts running trough the method, and when it hits a yield return it pauses execution and returns that item for you to use in your foreach. Then you request the next item, it resumes the code where it left and repeats the cycle until it encounters either yield break or the end of the method.
public IEnumerator<string> enumerateSomeStrings()
{
yield return "one";
yield return "two";
var array = new[] { "three", "four" }
foreach (var item in array)
yield return item;
yield return "five";
}
Take a look at the IEnumerator<T> interface; that may well to clarify what's happening. The compiler takes your code and turns it into a class that implements both IEnumerable<T> and IEnumerator<T>. The call to GetEnumerator() simply returns the class itself.
The implementation is basically a state machine, which, for each call to MoveNext(), executes the code up until the next yield return and then sets Current to the return value. The foreach loop uses this enumerator to walk through the enumerated items, calling MoveNext() before each iteration of the loop. The compiler is really doing some very cool things here, making yield return one of the most powerful constructs in the language. From the programmer's perspective, it's just an easy way to lazily return items upon request.
Yes thats right, heres the example from MSDN that illustrates how to use it
public class List
{
//using System.Collections;
public static IEnumerable Power(int number, int exponent)
{
int counter = 0;
int result = 1;
while (counter++ < exponent)
{
result = result * number;
yield return result;
}
}
static void Main()
{
// Display powers of 2 up to the exponent 8:
foreach (int i in Power(2, 8))
{
Console.Write("{0} ", i);
}
}
}
/*
Output:
2 4 8 16 32 64 128 256
*/
If I understand your question correct then your understanding is incorrect I'm affraid. The yield statements (yield return and yield break) is a very clever compiler trick. The code in you method is actually compiled into a class that implements IEnumerable. An instance of this class is what the method will return. Let's Call the instance 'ins' when calling ins.GetEnumerator() you get an IEnumerator that for each Call to MoveNext() produced the next element in the collection (the yield return is responsible for this part) when the sequence has no more elements (e.g. a yield break is encountered) MoveNext() returns false and further calls results in an exception. So it is not the Call to GetEnumerator that produced the (next) element but the Call to MoveNext
It looks like you understand it.
yield is used in your class's GetEnumerator as you describe so that you can write code like this:
foreach (MyObject myObject in myObjectCollection)
{
// Do something with myObject
}
By returning the first item from the 1st call the second from the 2nd and so on you can loop over all elements in the collection.
yield is defined in MyObjectCollection.
The Simple way to understand yield keyword is we do not need extra class to hold the result of iteration when return using
yield return keyword. Generally when we iterate through the collection and want to return the result, we use collection object
to hold the result. Let's look at example.
public static List Multiplication(int number, int times)
{
List<int> resultList = new List<int>();
int result = number;
for(int i=1;i<=times;i++)
{
result=number*i;
resultList.Add(result);
}
return resultList;
}
static void Main(string[] args)
{
foreach(int i in Multiplication(2,10))
{
Console.WriteLine(i);
}
Console.ReadKey();
}
In the above example, I want to return the result of multiplication of 2 ten times. So I Create a method Multiplication
which returns me the multiplication of 2 ten times and i store the result in the list and when my main method calls the
multiplication method, the control iterates through the loop ten times and store result result in the list. This is without
using yield return. Suppose if i want to do this using yield return it looks like
public static IEnumerable Multiplication(int number, int times)
{
int result = number;
for(int i=1;i<=times;i++)
{
result=number*i;
yield return result;
}
}
static void Main(string[] args)
{
foreach(int i in Multiplication(2,10))
{
Console.WriteLine(i);
}
Console.ReadKey();
}
Now there is slight changes in Multiplication method, return type is IEnumerable and there is no other list to hold the
result because to work with Yield return type must be IEnumerable or IEnumerator and since Yield provides stateful iteration
we do not need extra class to hold the result. So in the above example, when Multiplication method is called from Main
method, it calculates the result in for 1st iteration and return the result to main method and come backs to the loop and
calculate the result for 2nd iteration and returns the result to main method.In this way Yield returns result to calling
method one by one in each iteration.There is other Keyword break used in combination with Yield that causes the iteration
to stop. For example in the above example if i want to calculate multiplication for only half number of times(10/2=5) then
the method looks like this:
public static IEnumerable Multiplication(int number, int times)
{
int result = number;
for(int i=1;i<=times;i++)
{
result=number*i;
yield return result;
if (i == times / 2)
yield break;
}
}
This method now will result multiplication of 2, 5 times.Hope this will help you understand the concept of Yield. For more
information please visit http://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx

Categories