The Mystery Behind 'Yield'
If you've been coding with .NET for awhile then you've most likely encountered a method that returns IEnumerable<T>
. If you're like me, you realize that this returns a list of items your can loop through and evaluate. If you ever dug into the code you may have found a funny looking return statement yield return
.
It's basically just an array, right? We're just returning each value as a collection to loop over aren't we? Well, it wouldn't be the first time that someone (as in myself) misunderstood the purpose of it but there really is a difference.
Let's look at a fairly common example of returning collections.
The Usual Suspects
private string[] _Names = { "Joe", "Mary", "Bob" }; //a collection of names using a string array public string[] GetResultsAsArray() { List<string> results = new List<string>(); foreach (string name in this._Names) { Console.WriteLine("In GetResultsAsArray() : {0}", name); results.Add(name); } return results.ToArray(); } //a collection of names using IEnumerable<string> public IEnumerable<string> GetResultsAsEnumerable() { foreach (string name in this._Names) { Console.WriteLine("In GetResultsAsEnumerable() : {0}", name); yield return name; } }
This is two common looking examples. The first is similar to what that joker on StackOverflow had said in the link above. The second uses yield return
to return results.
So if we were to assign these values to a variable, what would our Console read?
var array = GetResultsAsArray(); var enumerable = GetResultsAsEnumerable(); Console.ReadKey();
In GetResultsAsArray() : Joe In GetResultsAsArray() : Mary In GetResultsAsArray() : Bob
Now, the first time I came across this I was shocked - I know I assigned my results -- what happened?
As it turns out, there is this little thing called lazy evaluation in play here - Unless we need it, the method doesn't get called. And since we aren't using our results anywhere, the method is never actually executed.
Lazy Yet Eager
So we've determined that unless we use the results of our method, the method won't ever be executed, which on one hand is actually really quite a handy feature.
Now here is another question for you, when we do use our results -- what happens then? Consider this little bit of code.
Console.WriteLine("Array -- "); foreach (string result in GetResultsAsArray()) { Console.WriteLine("In the array loop : " + result); } Console.WriteLine("\nEnumerable -- "); foreach (string result in GetResultsAsEnumerable()) { Console.WriteLine("In the enumerable loop : " + result); } Console.ReadKey();
... and with the following results ...
Array -- In GetResultsAsArray() : Joe In GetResultsAsArray() : Mary In GetResultsAsArray() : Bob In the array loop : Joe In the array loop : Mary In the array loop : Bob Enumerable -- In GetResultsAsEnumerable() : Joe In the enumerable loop : Joe In GetResultsAsEnumerable() : Mary In the enumerable loop : Mary In GetResultsAsEnumerable() : Bob In the enumerable loop : Bob
Each time yield return
sent a value back to our loop it was evaluated immediately! For being lazy code, this certainly was quick to give us our answers!
Lazy -- And Maybe Late For The Party
Here's an example where being lazy will get you into trouble, especially if you aren't clear what it does.
IEnumerable<SearchResult> results; using (SearchEngine search = new SearchEngine()) { results = search.GetEnumerableSearchResults(); } foreach(SearchResult item in results) { //KABOOM!! }
So what's wrong with this code? I'll tell you what - It's that lazy, good-for-nothing call to GetEnumerableSearchResults(), that's what!
Since our code doesn't get evaluated until after we've already disposed our object, there isn't anything there when the method is finally called! Looks like someone kicked into gear a little too late.
Of course code like this has many practical uses, so just make sure that you use it correctly and you'll find it to be a valuable addition to your programming tool kit.
So as it turns out there really is a difference between the two, and don't let any of those fools on StackOverflow tell you otherwise, even if that fool is me!.
July 13, 2009
The Mystery Behind 'Yield'
Post titled "The Mystery Behind 'Yield'"