“Yield return” is a powerful and handy statement if you want to quickly and easily an iteratable list without creating an Array or a List first:
using System; using System.Collections.Generic; using System.Drawing; class Program { static void Main() { var colors = Rainbow; Console.WriteLine("colors.GetType(): {0}", colors.GetType()); Console.WriteLine(); foreach (Color color in colors) { Console.WriteLine(color.Name); } Console.ReadLine(); } static IEnumerable<Color> Rainbow { get { yield return (Color.Red); yield return (Color.Orange); yield return (Color.Yellow); yield return (Color.Green); yield return (Color.LightBlue); yield return (Color.Indigo); yield return (Color.Violet); } } }
Red Orange Yellow Green LightBlue Indigo Violet
The .NET compiler then creates the necessary IEnumerable- and IEnumerator-implementing classes and the state machine in the background and everything is fine and clear.
Another use case would be to transform an existing List somehow into another List, for example a List<Color> into a List<String>:
using System; using System.Collections.Generic; using System.Drawing; class Program { static void Main() { var colors = Rainbow; Console.WriteLine("colors.GetType(): {0}", colors.GetType()); Console.WriteLine(); var colorNames = GetColorNames(colors); Console.WriteLine("colorNames.GetType(): {0}", colorNames.GetType()); Console.WriteLine(); foreach (String colorName in colorNames) { Console.WriteLine(colorName); } Console.ReadLine(); } static IEnumerable<String> GetColorNames(IEnumerable<Color> source) { foreach (Color color in source) { yield return (color.Name); } } static IEnumerable<Color> Rainbow { get { yield return (Color.Red); yield return (Color.Orange); yield return (Color.Yellow); yield return (Color.Green); yield return (Color.LightBlue); yield return (Color.Indigo); yield return (Color.Violet); } } }
Although you should consider if the Linq function Select() wouldn’t be better suited for this job:
using System; using System.Collections.Generic; using System.Drawing; using System.Linq; class Program { static void Main() { var colors = Rainbow; Console.WriteLine("colors.GetType(): {0}", colors.GetType()); Console.WriteLine(); var colorNames = Rainbow.Select(color => color.Name); Console.WriteLine("colorNames.GetType(): {0}", colorNames.GetType()); Console.WriteLine(); foreach (String colorName in colorNames) { Console.WriteLine(colorName); } Console.ReadLine(); } static IEnumerable<Color> Rainbow { get { yield return (Color.Red); yield return (Color.Orange); yield return (Color.Yellow); yield return (Color.Green); yield return (Color.LightBlue); yield return (Color.Indigo); yield return (Color.Violet); } } }
But “yield return” becomes dangerous when classes come into play that implement IDisposable. Because now you need to understand what exactly the compiler is doing and if you’ve cut your methods along the right lines. Or if it would be more sensible to not use “yield return” in this case altogether. “Yield return” – like Linq – uses deferred execution, which means that the code in the method isn’t executed when the method is called but rather when the iterator starts its work. But it’s possible that at that moment the IDisposable class is already disposed and the iterator will grasp at nothing
To show what the compiler is actually doing with a “yield return” and why it is relevant how the IDisposable and the iterator are related, I’ve implemented twi sample applications. The first one uses “yield return” and fails at first and then uses it sucessfully. The second one is showing what the compiler is actually doing by me having implemented the IEnumerable and the IEnumerator by myself in the same way the compiler would have done it for “yield return”.
Both programs are identical on the logical level so you can debug where the differences between a working and a faulty “yield return” are.