c# contextual keywords: yield

yield is a contextual keywords. When it shows in a statement, it means the method or get accessor in which it appears is an iterator. Thus it provides a simple way to define an iterator, rather than a class that implements IEnumerable or IEnumerator.

When you use the yield contextual keyword in a statement, you indicate that the method, operator, or get accessor in which it appears is an iterator. Using yield to define an iterator removes the need for an explicit extra class (the class that holds the state for an enumeration, see IEnumerator for an example) when you implement the IEnumerable and IEnumerator pattern for a custom collection type.

Grammar

1
2
yield return expression;	// return an element in the iterator
yield break; // end the iterator

Q & A

What’s an iterator?

An iterator means that it can be looped in foreach or LINQ query. In this case, it means the method or get accessor containing yield can be consumed by foreach or LINQ query.

what does yield means in this iterator?

The yield return will return an element in the iterator. During the loop, the iterator use MoveNext to get i (take power method as an example), and the MoveNext stop at the next yield return expression, and the Current property of the iterator is updated as this value, too.

when does the iterator stopped?

  • when there’s yield break
  • when the method body is end

what’s the requirements to define such iterator?

  • The return type must be IEnumerable, IEnumerable, IEnumerator, or IEnumerator.
  • The declaration can’t have any in ref or out parameters.
  • Don’t use yield in Lambda expressions and anonymous methods.
  • Don’t use yield in methods that contain unsafe blocks. For more information, see unsafe.
  • Don’t use yield return in a try-catch block. A yield return statement can be located in the try block of a try-finally statement.
  • yield break can be located in a try block or a catch block but not a finally block

examples

yield in method

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
static void Main(string[] args)
{
var powers = Power(2, 10); // won't execute the body of Power
foreach (var i in powers)
{
Console.WriteLine($"{i} ");
}
}

// =================== yield in method ========================
public static IEnumerable<int> Power(int number, int exponent)
{
int result = 1;
for (int i = 0; i < exponent; i++)
{
result = result * number;
yield return result;
}
}

yield in get accessor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
static void Main(string[] args)
{
foreach (var i in new Galaxies().AllGalaxies)
{
Console.WriteLine($"{i.Name}, {i.Age}");
}
}

class Galaxies
{
// =================== yield in get accessor ========================
public IEnumerable<Galaxy> AllGalaxies
{
get
{
yield return new Galaxy("The milky way", 1000);
yield return new Galaxy("Tadpole", 1000);
yield return new Galaxy("Andromeda", 1000);
}
}
}

class Galaxy
{
public string Name { get; }
public int Age { get; }

public Galaxy(string name, int age)
{
Name = name;
Age = age;
}
}