1. Functions implemented by yield
yield return:
Let's take a look at the following code, which implements a function similar to traversing an array with foreach through yield return, indicating that yield return is also used to implement the function of the iterator.
yield break:
Looking at the code below, only 1 and 2 are output, but not 3, indicating that the iterator was stopped by yield break, so yield break is used to terminate iteration.
2. It can only be used in <T><T>methods, operators, get accessors that must return an IEnumerable, IEnumerable, IEnumerator, or IEnumerator.
3. The implementation principle of yield keyword
We replaced the foreach loop with a while loop and found that although we didn't implement GetEnumerator(), nor did we implement the corresponding IEnumerator's MoveNext(), and Current properties, we still worked with these functions.
As for why this is the case, we can use ILSpy to decompile the generated exe to find the reason.
Since direct decompilation to C# will become as it is
Therefore, we chose to decompile it into IL code with C# annotations, although the readability is poor, but we can understand the principles in detail. Let's first look at the translation of the program, a new class is automatically generated during compilation.
Let's take a closer look at the code, and EnumerableFuc() returns this new class.
Looking at the implementation of the class that this code generates automatically, we can see that it inherits IEnumerable<T>, IEnumerable, IEnumerator, or IEnumerator, and we <T>should be able to guess that this new class is the reason why we don't implement the corresponding IEnumerator's MoveNext() and Current properties, but we can still use these functions normally.
Let's take a look at how this class iterates, let's mainly look at the MoveNext() function
Each call to the MoveNext() function adds 1 to the state, and a total of 4 iterations are made, the first three returning true and the last returning false, which means the end of the iteration. These four iterations correspond to the statements in enumberableFuc() that are divided into 4 parts by 3 yield return statements.
The real process of iterating with enumberableFuc() is:
1. Run the enumberableFuc() function to get an instance of the class automatically generated by the code. 2. Then call the GetEnumberator() function to start iterating on the acquired class itself as an iterator. 3. Each time you run MoveNext(), the state increases by 1, and the switch statement allows you to execute different parts of the code every time you call MoveNext(). 4。 MoveNext() returns false, ending. This also shows that the yield keyword is actually a syntactic sugar, and it is ultimately an iterative function implemented by implementing IEnumberable<T>, IEnumberable, <T>IEnumberator, and IEnumberator interfaces.
|