This question already has answers here:
What is the yield keyword used for in C#?
(19 answers)
Closed 4 years ago.
I have the code below:
static IEnumerable<int> YieldReturn()
{
yield return 1;
yield return 2;
yield return 3;
}
static void Main(string[] args)
{
// Lets see how yield return works
foreach (int i in YieldReturn())
{
Console.WriteLine(i);
}
}
I have a couple of questions:
1-How many times does YieldReturn() get called? one or three times?
2-If YieldReturn() get called three times, how does IEnumerable store value 1, 2 and 3?
yield is used for lazy evaluation - it is only executed in enumeration. Your method YieldReturn() will be called once and then be enumerated by your foreach loop, providing the values in the order in which you yielded them.
Note that this example gains nothing from yield - it works best when you can defer execution of something expensive to an eventual enumeration. To immediately enumerate on the method call gains nothing for you.
Related
This question already has answers here:
Convert a list to a string in C#
(14 answers)
Closed 9 months ago.
I am a mere beginner and I am trying to learn a bit of LINQ. I have a list of values and I want to receive a different list based on some computation. For example, the below is often quoted in various examples across the Internet:
IEnumerable<int> squares = Enumerable.Range(1, 10).Select(x => x * x);
here the "computation" is done by simply multiplying a member of the original list by itself.
I wanted to actually use a method that returns a string and takes x as an argument.
Here is the code I wrote:
namespace mytests{
class program {
static void Main (string[] args)
{
List<string> nums = new List<string>();
nums.Add("999");
nums.Add("888");
nums.Add("777");
IEnumerable<string> strings = nums.AsEnumerable().Select(num => GetStrings(num));
Console.WriteLine(strings.ToString());
}
private static string GetStrings (string num){
if (num == "999")
return "US";
else if (num == "888")
{
return "GB";
}
else
{
return "PL";
}
}
}
}
It compiles but when debugging, the method GetStrings is never accessed and the strings object does not have any members. I was expecting it to return "US", "GB", "PL".
Any advice on what I could be doing wrong?
Thanks.
IEnumerable<string>.ToString() method does not work as you expected. Result will be
System.Collections.Generic.List`1[System.String]
If you want to see the values which are held in the collection, you should create iteration.
foreach (var i in strings)
Console.WriteLine(i);
This line does two things for you. One of them is writing the values which are held in the collection to console. The other operation is iterating the collection. During iteration, values are needed and linq will execute the necessary operation (in your case GetStrings method).
Currently your code does not use the collection values, so the code does not evaluate the values and does not trigger GetStrings method.
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();
I am trying to understand use of Yield to enumerate the collection. I have written this basic code:
static void Main(string[] args)
{
Iterate iterate = new Iterate();
foreach (int i in iterate.EnumerateList())
{
Console.Write("{0}", i);
}
Console.ReadLine();
}
class Iterate
{
public IEnumerable<int> EnumerateList()
{
List<int> lstNumbers = new List<int>();
lstNumbers.Add(1);
lstNumbers.Add(2);
lstNumbers.Add(3);
lstNumbers.Add(4);
lstNumbers.Add(5);
foreach (int i in lstNumbers)
{
yield return i;
}
}
}
(1) What if I use simply return i instead of yield return i?
(2) What are the advantages of using Yield and when to prefer using it?
Edited **
In the above code, I think it is an overhead to use foreach two times. First in the main function and the second in the EnumerateList method.
Using yield return i makes this method an iterator. It will create an IEnumerable<int> sequence of values from your entire loop.
If you used return i, it would just return a single int value. In your case, this would cause a compiler error, as the return type of your method is IEnumerable<int>, not int.
In this specific example, I would personally just return lstNumbers instead of using the iterator. You could rewrite this without the list, though, as:
public IEnumerable<int> EnumerateList()
{
yield return 1;
yield return 2;
yield return 3;
yield return 4;
yield return 5;
}
Or even:
public IEnumerable<int> EnumerateList()
{
for (int i=1;i<=5;++i)
yield return i;
}
This is very handy when you're making a class which you want to act like a collection. Implementing IEnumerable<T> by hand for a custom type often requires making a custom class, etc. Prior to iterators, this required a lot of code, as shown in this old sample for implementing a custom collection in C#.
As Reed says using yield allows you to implement an iterator. The major advantage of an iterator is that it allows lazy evaluation. I.e. it doesn't have to materialize the entire result unless needed.
Consider Directory.GetFiles from the BCL. It returns string[]. I.e. it has to get all the files and put the names in an array before it returns. In contrast Directory.EnumerateFiles returns IEnumerable<string>. I.e. the caller is responsible for handling the result set. That means that the caller can opt out of enumerating the collection at any point.
The yield keyword will make the compiler turn the function into an enumerator object.
The yield return statement doesn't simply exit the function and return one value, it leaves the code in a state so that it can be resumed at that point when the next value is requested from the enumerator.
You can't return just i as i is an int and not an IEnumerable. It won't even compile. You could have returned lstNumbers as that implements the interface of IEnumerable.
I prefer yield return since the compiler will handle building the enumerable and not having to build the list in the first place. So for me if I have something that is already implementing the interface then I return that if I have to build it and not use it else where then I yield return.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Proper Use of yield return
What is the use of the yield keyword in C#?
I didn't understand it from the MSDN reference... can someone explain it to me please?
I'm going to try and give you an example
Here's the classical way of doing, which fill up a list object and then returns it:
private IEnumerable<int> GetNumbers()
{
var list = new List<int>();
for (var i = 0; i < 10; i++)
{
list.Add(i);
}
return list;
}
the yield keyword returns items one by one like this :
private IEnumerable<int> GetNumbers()
{
for (var i = 0; i < 10; i++)
{
yield return i;
}
}
so imagine the code that calls the GetNumbers function as following:
foreach (int number in GetNumbers())
{
if (number == 5)
{
//do something special...
break;
}
}
without using yield you would have to generate the whole list from 0-10 which is then returned, then iterated over until you find the number 5.
Now thanks to the yield keyword, you will only generate numbers until you reach the one you're looking for and break out the loop.
I don't know if I was clear enough..
my question is, when do I use it? Is there any example out there where I have there is no other choice but using yield? Why did someone feel C# needed another keyword?
The article you linked provided a nice example of when and how it is used.
I hate to quote an article you yourself linked too, but incase it's too long, and you didn't read it.
The yield keyword signals to the compiler that the method in which it appears is an iterator block. The compiler generates a class to implement the behavior that is expressed in the iterator block.
public static System.Collections.IEnumerable Power(int number, int exponent)
{
int counter = 0;
int result = 1;
while (counter++ < exponent)
{
result = result * number;
yield return result;
}
}
In the above example, the yield statement is used inside an iterator block. When the Power method is invoked, it returns an enumerable object that contains the powers of a number. Notice that the return type of the Power method is System.Collections.IEnumerable, an iterator interface type.
So the compiler automatically generates a IEnumerable interfaced based on the things that were yielded during the method's execution.
Here is a simplified example, for the sake of completeness:
public static System.Collections.IEnumerable CountToTen()
{
int counter = 0;
while (counter++ < 10)
{
yield return counter;
}
}
public static Main(string[]...)
{
foreach(var i in CountToTen())
{
Console.WriteLine(i);
}
}
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