22.4 Yield sentence
The Yield statement is used for iterator blocks to generate an enumerator object value, or indicate the end of iteration.
Embedded-statement: (embedded statement) ... Yield-statement (Yield statement)
Yield-statement: (yield statement) Yield Return Expression; Yield Break;
To ensure compatibility with existing programs, Yield is not a reserved word, and Yield is only particularly significant before close to Return or Break keywords. In other context, it can be used as an identifier.
There are several constraints that the Yield statement can appear, as described below.
The L Yield statement appears outside the method, the operator, and the access device, will cause errors when compiling.
l Yield statement occurs within an anonymous method, will cause errors when compiling.
l Yield statement When you have a Finally statement of the TRY statement, it will cause errors when compiling.
The L Yield Return statement occurs anywhere in any of the TRY statements containing the CATCH spectrient, will result in compile time errors.
Some valid and invalid uses of Yield statements are shown as follows.
Delegate IEnumerable
IEnumerator
Try {yield return 3; // Error, Yield Return in Try ... catch Eld break; // ok} catch {yield return 4; // error, Yield Return In Try ... catch; OK}
D D = delegate {yield return 5; // error, Yield in anonymous method};
INT mymethod () {yield return 1; // error, error return type of iterator block}
From the Yield Return statement, the expression type to the generated type of iterator (§22.1.3), there must be implicit conversion (§6.1).
The Yield RetURN statement is executed as follows.
l The expression given in the statement will be calculated, implicitly converted to the generating type, and is assigned the CURRENT property of the enumerator object.
l The execution of the iterator block will be suspended. If the Yield Return statement is in one or more TRY blocks, the Finally block associated with it will not be executed.
l The MoveNext method of the envelope object returns true to the caller, indicating that the enumerator object is successfully advanced to the next item.
The next call of the MoveNext method of the enumerator object is resended from the place where the iterator block hangs.
The YELD BREAK statement is executed as follows.
l If the Yield Break statement is included in a TRY block with a Finally block, the initial control will be transferred to the Finally block of the most inside the TRY statement. When controlling the end point of the FINALLY block, the control will be transferred to the next nearest TRY Finally block. This process will be repeated until all the Finally blocks of all internal TRY statements are executed. l Control returns the caller of the iterator block. This may be due to the MoveNext method of the enumerator object or the Dispose method.
Since the Yield Break statement is unconditional transfer control, the endpoint of the Yield Break statement will never arrive.
22.4.1 Clear assignment
For Yield Return statement STMT in the form of Yield Return EXPR
L Like Stmt, the beginning variable V at EXPR has a clear assignment state at the beginning variable V.
l If the end point V is explicitly assigned at the EXPR, it will also be explicitly assigned at the end point of the STMT; otherwise, the end point at the STMT will not be explicitly assigned.
22.5 Implementation example
This section describes the possible implementation of the iterator in the form of a standard C # component. The implementation described herein is based on the same principles as the Microsoft C # compiler, but this is by no means for mandatory or unique possible implementation.
The following STACK
Using system.collections; usneric;
Class Stack
Public void push (t item) {if (items == null) {items = new t [4];} else if (items.length == count) {t [] newItems = new t [count * 2]; array .Copy (items, 0, newItems, 0, count); items = newItems;} items [count ] = item;}
Public T Pop () {t result = items [- count]; items [count] = t.default; returnrate;}
Public IEnumerator
The GetENUMERATOR method can be converted to an instance of an enumerator class generated by the compiler, which encapsulates the code in the iterator block, as shown below.
Class Stack
Public IEnumerator
Class __enumerator1: ienumerator
Public __enumerator1 (stack
Object ienumerator.current {get {return__current;}}
Public Bool MoveNext () {switch (__state) {case 1: goto __state1; case 2: goto __state2;} i = __this.count - 1; __loop: if (i <0) goto __state2; __current = __this.items [i ]; __State = 1; return true; __state1: --i; goto __loop; __state2: __State = 2; return false;}
Public void dispose () {__State = 2;
Void IEnumerator.reset () {throw new notSupportedException ();}} The code within the iterator block is converted to State Machine and is placed in the MoveNext method of the enumerator class. Furthermore, the local variable i is converted into a field of an enumerator object, so it can last in the calling process of MOVENEXT.
The following example prints a simple multiplication table from integers 1 to 10. In this example, the FROMTO method returns an enumerable object and is implemented using an iterator.
Using system.collections.Generic;
Class test {static {{while (from <= to) Yield Return from ;}
Static void
Main
() {IEnumerable
The FROMTO method can be converted into an example of an enumerable class generated by the compiler, which encapsulates the code in the iterator block, as shown below.
Using system.chreading; using system.collections; usneric;
Class test {...
static IEnumerable
Public __enumerable11 (int __from, int to) {this .__ from = __from; this.to = to;}
public IEnumerator
IEnumerator ienumerable.getenumerator () {return (ienumerator) getenumerator ();
Public int current {get {return __current;}}
Object ienumerator.current {get {return__current;}}
public bool MoveNext () {switch (__state) {case 1: if (from> to) goto case 2; __current = from ; __state = 1; return true; case 2: __state = 2; return false; default: throw new InvalidOperationException ();
Public void dispose () {__State = 2;
Void IEnumerator.reset () {throw new notsupportedException ();}}}
This enumeration class implements an enumerated interface and an enumerator interface, which makes it an enumerable or enumerator. When the GetEnumerator method is first called, it will return to an enumerated object itself. Subsequent GetEnumerator calls, if any, all returns a copy of the enumerable object. Therefore, each returned enumerator has its own state, changing an enumerator will not affect the other. Interlocked.CompareExchange method is used to ensure a thread security operation. The from and the to parameters are converted to the enumerable field. Since the FROM is modified within the iterator block, another __FROM field is introduced to save the initial value of the FROM in each enumerated.
If__state is 0, MoveNext is called, the method will throw an InvalidOperationException exception. This will prevent the GetENUMERATOR that is not first called, and the object can be enumerated as an enumerator.
(C # 2.0 Specification full text)
Calling ... & ^% finally finished, should rest, huh, huh, eyes splashing ** && ^ %% ...