Monday 1 August 2016

c# - Difference between yield and List.AsEnumerable



Yield is something I find tough to understand till now. But now I am getting a hold of it. Now, in a project, if I return List, Microsoft code analysis will give a warning about it. So, normally I'll do all the necessary logical parts and return the list as IEnumerable. I want to know the difference between the two. Means if I am doing yield return or otherwise.



Here is a very simple example I am showing, normally the code is a little bit complicated.



private static IEnumerable getIntFromList(List inputList)
{

var outputlist = new List();
foreach (var i in inputList)
{
if (i %2 ==0)
{
outputlist.Add(i);
}
}

return outputlist.AsEnumerable();

}

private static IEnumerable getIntFromYeild(List inputList)
{
foreach (var i in inputList)
{
if (i%2 == 0)
{
yield return i;
}

}
}


One significant benefit I can see is fewer lines. But is there any other benefit? Should I change and update my functions which are returning IEnumearble to use yield instead of List? What is the best way or a better way to do things?



Here, I can use simple lambda expressions over List, but normally that is not the case, this example is specifically to understand best approach of coding.


Answer



Your first example is still doing all the work eagerly and building up a list in memory. In fact, the call to AsEnumerable() is pointless - you might as well use:




return outputlist;


Your second example is lazy - it only does as much work as it needs to as the client pulls data from it.



The simplest way to show the difference is probably to put a Console.WriteLine call inside the if (i % 2 == 0) statement:



Console.WriteLine("Got a value to return: " + i);



Then if you also put a Console.WriteLine call in the client code, e.g.



foreach (int value in getIntFromList(list))
{
Console.WriteLine("Received value: " + value);
}


... you'll see that with your first code, you see all the "Got a value" lines first, then all the "Received value" lines. With the iterator block, you'll see them interleaved.




Now imagine that your code is actually doing something expensive, and your list is very long, and the client only wants the first 3 values... with your first code, you'd be doing a load of irrelevant work. With the lazy approach, you only do as much work as you need to, in a "just in time" fashion. The second approach also doesn't need to buffer all the results up in memory - again, if the input list is very large, you'd end up with a large output list too, even if you only wanted to use a single value at a time.


No comments:

Post a Comment

c++ - Does curly brackets matter for empty constructor?

Those brackets declare an empty, inline constructor. In that case, with them, the constructor does exist, it merely does nothing more than t...