yield (C# Reference)
Updated: October 2008
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. In the iterator block, the yield keyword is used together with the return keyword to provide a value to the enumerator object. This is the value that is returned, for example, in each loop of a foreach statement. The yield keyword is also used with break to signal the end of iteration. For more information about iterators, see Iterators (C# Programming Guide). The following example shows the two forms of the yield statement.
yield return <expression>; yield break;
In a yield return statement, expression is evaluated and returned as a value to the enumerator object; expression has to be implicitly convertible to the yield type of the iterator.
In a yield break statement, control is unconditionally returned to the caller of the iterator, which is either the IEnumerator.MoveNext method (or its generic System.Collections.Generic.IEnumerable<T> counterpart) or the Dispose method of the enumerator object.
The yield statement can only appear inside an iterator block, which can be implemented as the body of a method, operator, or accessor. The body of such methods, operators, or accessors is controlled by the following restrictions:
-
Unsafe blocks are not allowed.
-
Parameters to the method, operator, or accessor cannot be ref or out.
-
A yield return statement cannot be located anywhere inside a try-catch block. It can be located in a try block if the try block is followed by a finally block.
-
A yield break statement may be located in a try block or a catch block but not a finally block.
A yield statement cannot appear in an anonymous method. For more information, see Anonymous Methods (C# Programming Guide).
When used with expression, a yield return statement cannot appear in a catch block or in a try block that has one or more catch clauses. For more information, see Exception Handling Statements (C# Reference).
In the following example, the yield statement is used inside an iterator block, which is the method Power(int number, int power). 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.
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 */
For more information, see the following sections in the C# Language Specification:
-
19.3 Iterators
-
22 Iterators
Option Explicit On
Option Infer Off
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim results As System.Collections.Generic.IEnumerable(Of Integer)
results = Power(2, 8)
Dim sb As New System.Text.StringBuilder
For Each num As Integer In results
sb.Append(num.ToString & " ")
Next
MessageBox.Show(sb.ToString)
End Sub
Public Function Power(ByVal number As Integer, ByVal exponent As Integer) As System.Collections.Generic.IEnumerable(Of Integer)
Dim result As New List(Of Integer)
For index As Integer = 1 To exponent
result.Add(Convert.ToInt32(Math.Pow(number, index)))
Next
Return result.AsEnumerable
End Function
End Class
- 9/6/2011
- John Anthony Oliver
- 9/6/2011
- John Anthony Oliver
The above article states:
"The yield statement can only appear inside an iterator block..."
Correct me if I'm wrong, but in actuality, the yield break; statement does appear outside an iterator block. Perhaps slightly better wording would be:
"The yield return statement can only appear inside an iterator block..."
Aaron
CS Team: Hi Aaron. Thanks for your comment. The C# 4.0 Language Spec (http://www.microsoft.com/downloads/details.aspx?FamilyID=dfbf523c-f98c-4804-afbd-459e846b268e&displaylang=en#filelist) says the following:
8.14 The yield statement
The yield statement is used in an iterator block (§8.2) to yield a value to the enumerator object (§10.14.4) or enumerable object (§10.14.5) of an iterator or to signal the end of the iteration.
yield-statement:
yieldreturn expression ;
yieldbreak;
- 10/2/2009
- Limited Atonement
- 5/7/2010
- SJ at MSFT
Here is a blog that explains the usage of yield return and yield break in a simple example
http://iserialized.com/a-quick-start-guide-to-yield-return-and-yield-break/
- 1/7/2010
- Cleancoder
- 3/11/2010
- One Developer
- 11/4/2009
- Alex_82
- 11/2/2009
- jaime_olivares
"The yield keyword uses what's known as lazy evaluation. What this means practically is that anything following a "yield return" will not be evaluated until it is requested from the enumerator."
should have been at the very beginning of this article. Because it explains everything in several words. Very clear and concise.
It is sooo true about many articles on MSDN, they start explaning from the middle.
- 10/9/2009
- jhhhj
The yield keyword uses what's known as lazy evaluation. What this means practically is that anything following a "yield return" will not be evaluated until it is requested from the enumerator. Take the following class for example:
public class ExampleClass{
public List<string> OriginalStrings { get; set; }
/// <summary>
/// Returns an enumerated list of reversed strings from OriginalStrings.
/// Causes side effects due to the call to "reverseString".
/// </summary>
/// <returns></returns>
public IEnumerable<string> GetReversedStrings()
{
for (int i = 0; i < OriginalStrings.Count; i++)
yield return reverseString(i);
}
/// <summary>
/// Replaces the string at the specified index with a reversed version of itself.
/// </summary>
/// <param name="index">The index of the string in OriginalStrings to reverse. </param>
/// <returns>The newly reversed string</returns>
private string reverseString(int index)
{
string value = OriginalStrings[index];
char[] chars = value.ToCharArray();
Array.Reverse(chars);
string[] letters = new string[chars.Length];
for (int i = 0; i < chars.Length; i++)
letters[i] = chars[i].ToString();
string returnValue = string.Join("", letters);
OriginalStrings[index] = returnValue;
return OriginalStrings[index];
}
}
The GetReversedStrings method will yield the result of the call to reverseString, which will set the values of the OriginalStrings to their reversed equivalent, and return the newly reversed string.
Now, let's call this from the main method:
static void Main(string[] args)
{
ExampleClass exampleClass = new ExampleClass();
exampleClass.OriginalStrings = new List<string>() { "Bob", "David", "Jimenez", "Franz" };
exampleClass.GetReversedStrings();
foreach (string s in exampleClass.OriginalStrings)
Console.WriteLine(s);
Console.ReadLine();
}
Notice the output. The strings are not reversed. This is because the result of GetReversedStrings() is never iterated through.
Let's alter the code just a bit.
static void Main(string[] args)
{
ExampleClass exampleClass = new ExampleClass();
exampleClass.OriginalStrings = new List<string>() { "Bob", "David", "Jimenez", "Franz" };
foreach (string value in exampleClass.GetReversedStrings())
{
// do nothing of consequence. This is here simply to iterate through the values.
}
foreach (string s in exampleClass.OriginalStrings)
Console.WriteLine(s);
Console.ReadLine();
}
Now, you'll see a different result when you run this. All of the values will print out reversed. This is because the call to the statement returned in the yield return statement is evaluated only when iterated through.
This can certainly be an advantage, as it is in Linq, but use the keyword improperly, and you might get unexpected results.
- 4/1/2009
- David M Morton