Iteration statements repeatedly execute an embedded statement.
iteration-statement:
while-statement
do-statement
for-statement
foreach-statement
8.8.1The while statement
The while statement conditionally executes an embedded statement zero or more times.
while-statement:
while ( boolean-expression ) embedded-statement
A while statement is executed as follows:
-
The boolean-expression (§7.19) is evaluated.
-
If the boolean expression yields true, control is transferred to the embedded statement. When and if control reaches the end point of the embedded statement (possibly from execution of a continue statement), control is transferred to the beginning of the while statement.
-
If the boolean expression yields false, control is transferred to the end point of the while statement.
Within the embedded statement of a while statement, a break statement (§8.9.1) may be used to transfer control to the end point of the while statement (thus ending iteration of the embedded statement), and a continue statement (§8.9.2) may be used to transfer control to the end point of the embedded statement (thus performing another iteration of the while statement).
The embedded statement of a while statement is reachable if the while statement is reachable and the boolean expression does not have the constant value false.
The end point of a while statement is reachable if at least one of the following is true:
-
The while statement contains a reachable break statement that exits the while statement.
-
The while statement is reachable and the boolean expression does not have the constant value true.
8.8.2The do statement
The do statement conditionally executes an embedded statement one or more times.
do-statement:
do embedded-statement while ( boolean-expression ) ;
A do statement is executed as follows:
-
Control is transferred to the embedded statement.
-
When and if control reaches the end point of the embedded statement (possibly from execution of a continue statement), the boolean-expression (§7.19) is evaluated. If the boolean expression yields true, control is transferred to the beginning of the do statement. Otherwise, control is transferred to the end point of the do statement.
Within the embedded statement of a do statement, a break statement (§8.9.1) may be used to transfer control to the end point of the do statement (thus ending iteration of the embedded statement), and a continue statement (§8.9.2) may be used to transfer control to the end point of the embedded statement.
The embedded statement of a do statement is reachable if the do statement is reachable.
The end point of a do statement is reachable if at least one of the following is true:
-
The do statement contains a reachable break statement that exits the do statement.
-
The end point of the embedded statement is reachable and the boolean expression does not have the constant value true.
8.8.3The for statement
The for statement evaluates a sequence of initialization expressions and then, while a condition is true, repeatedly executes an embedded statement and evaluates a sequence of iteration expressions.
for-statement:
for ( for-initializeropt ; for-conditionopt ; for-iteratoropt ) embedded-statement
for-initializer:
local-variable-declaration
statement-expression-list
for-condition:
boolean-expression
for-iterator:
statement-expression-list
statement-expression-list:
statement-expression
statement-expression-list , statement-expression
The for-initializer, if present, consists of either a local-variable-declaration (§8.5.1) or a list of statement-expressions (§8.6) separated by commas. The scope of a local variable declared by a for-initializer starts at the local-variable-declarator for the variable and extends to the end of the embedded statement. The scope includes the for-condition and the for-iterator.
The for-condition, if present, must be a boolean-expression (§7.19).
The for-iterator, if present, consists of a list of statement-expressions (§8.6) separated by commas.
A for statement is executed as follows:
-
If a for-initializer is present, the variable initializers or statement expressions are executed in the order they are written. This step is only performed once.
-
If a for-condition is present, it is evaluated.
-
If the for-condition is not present or if the evaluation yields true, control is transferred to the embedded statement. When and if control reaches the end point of the embedded statement (possibly from execution of a continue statement), the expressions of the for-iterator, if any, are evaluated in sequence, and then another iteration is performed, starting with evaluation of the for-condition in the step above.
-
If the for-condition is present and the evaluation yields false, control is transferred to the end point of the for statement.
Within the embedded statement of a for statement, a break statement (§8.9.1) may be used to transfer control to the end point of the for statement (thus ending iteration of the embedded statement), and a continue statement (§8.9.2) may be used to transfer control to the end point of the embedded statement (thus executing the for-iterator and performing another iteration of the for statement, starting with the for-condition).
The embedded statement of a for statement is reachable if one of the following is true:
-
The for statement is reachable and no for-condition is present.
-
The for statement is reachable and a for-condition is present and does not have the constant value false.
The end point of a for statement is reachable if at least one of the following is true:
-
The for statement contains a reachable break statement that exits the for statement.
-
The for statement is reachable and a for-condition is present and does not have the constant value true.
The foreach statement enumerates the elements of a collection, executing an embedded statement for each element of the collection.
foreach-statement:
foreach ( local-variable-type identifier in expression ) embedded-statement
The type and identifier of a foreach statement declare the iteration variable of the statement. If the var keyword is given as the local-variable-type, the iteration variable is said to be an implicitly typed iteration variable, and its type is taken to be the element type of the foreach statement, as specified below. The iteration variable corresponds to a read-only local variable with a scope that extends over the embedded statement. During execution of a foreach statement, the iteration variable represents the collection element for which an iteration is currently being performed. A compile-time error occurs if the embedded statement attempts to modify the iteration variable (via assignment or the ++ and operators) or pass the iteration variable as a ref or out parameter.
The compile-time processing of a foreach statement first determines the collection type, enumerator type and element type of the expression. This determination proceeds as follows:
-
If the type X of expression is an array type then there is an implicit reference conversion from X to the System.Collections.IEnumerable interface (since System.Array implements this interface). The collection type is the System.Collections.IEnumerable interface, the enumerator type is the System.Collections.IEnumerator interface and the element type is the element type of the array type X.
-
Otherwise, determine whether the type X has an appropriate GetEnumerator method:
-
Perform member lookup on the type X with identifier GetEnumerator and no type arguments. If the member lookup does not produce a match, or it produces an ambiguity, or produces a match that is not a method group, check for an enumerable interface as described below. It is recommended that a warning be issued if member lookup produces anything except a method group or no match.
-
Perform overload resolution using the resulting method group and an empty argument list. If overload resolution results in no applicable methods, results in an ambiguity, or results in a single best method but that method is either static or not public, check for an enumerable interface as described below. It is recommended that a warning be issued if overload resolution produces anything except an unambiguous public instance method or no applicable methods.
-
If the return type E of the GetEnumerator method is not a class, struct or interface type, an error is produced and no further steps are taken.
-
Member lookup is performed on E with the identifier Current and no type arguments. If the member lookup produces no match, the result is an error, or the result is anything except a public instance property that permits reading, an error is produced and no further steps are taken.
-
Member lookup is performed on E with the identifier MoveNext and no type arguments. If the member lookup produces no match, the result is an error, or the result is anything except a method group, an error is produced and no further steps are taken.
-
Overload resolution is performed on the method group with an empty argument list. If overload resolution results in no applicable methods, results in an ambiguity, or results in a single best method but that method is either static or not public, or its return type is not bool, an error is produced and no further steps are taken.
-
The collection type is X, the enumerator type is E, and the element type is the type of the Current property.
-
Otherwise, check for an enumerable interface:
-
If there is exactly one type T such that there is an implicit conversion from X to the interface System.Collections.Generic.IEnumerable, then the collection type is this interface, the enumerator type is the interface System.Collections.Generic.IEnumerator, and the element type is T.
-
Otherwise, if there is more than one such type T, then an error is produced and no further steps are taken.
-
Otherwise, if there is an implicit conversion from X to the System.Collections.IEnumerable interface, then the collection type is this interface, the enumerator type is the interface System.Collections.IEnumerator, and the element type is object.
-
Otherwise, an error is produced and no further steps are taken.
The above steps, if successful, unambiguously produce a collection type C, enumerator type E and element type T. A foreach statement of the form
foreach (V v in x) embedded-statement
is then expanded to:
{
E e = ((C)(x)).GetEnumerator();
try {
V v;
while (e.MoveNext()) {
v = (V)(T)e.Current;
embedded-statement
}
}
finally {
… // Dispose e
}
}
The variable e is not visible to or accessible to the expression x or the embedded statement or any other source code of the program. The variable v is read-only in the embedded statement. If there is not an explicit conversion (§6.2) from T (the element type) to V (the type in the foreach statement), an error is produced and no further steps are taken. If x has the value null, a System.NullReferenceException is thrown at run-time.
An implementation is permitted to implement a given foreach-statement differently, e.g. for performance reasons, as long as the behavior is consistent with the above expansion.
The body of the finally block is constructed according to the following steps:
-
If there is an implicit conversion from E to the System.IDisposable interface, then the finally clause is expanded to the semantic equivalent of:
finally {
((System.IDisposable)e).Dispose();
}
except that if e is a value type, or a type parameter instantiated to a value type, then the cast of e to System.IDisposable will not cause boxing to occur.
-
Otherwise, if E is a sealed type, the finally clause is expanded to an empty block:
finally {
}
-
Otherwise, the finally clause is expanded to:
finally {
System.IDisposable d = e as System.IDisposable;
if (d != null) d.Dispose();
}
The local variable d is not visible to or accessible to any user code. In particular, it does not conflict with any other variable whose scope includes the finally block.
The order in which foreach traverses the elements of an array, is as follows: For single-dimensional arrays elements are traversed in increasing index order, starting with index 0 and ending with index Length – 1. For multi-dimensional arrays, elements are traversed such that the indices of the rightmost dimension are increased first, then the next left dimension, and so on to the left.
The following example prints out each value in a two-dimensional array, in element order:
using System;
class Test
{
static void Main() {
double[,] values = {
{1.2, 2.3, 3.4, 4.5},
{5.6, 6.7, 7.8, 8.9}
};
foreach (double elementValue in values)
Console.Write("{0} ", elementValue);
Console.WriteLine();
}
}
The output produced is as follows:
1.2 2.3 3.4 4.5 5.6 6.7 7.8 8.9
In the example
int[] numbers = { 1, 3, 5, 7, 9 };
foreach (var n in numbers) Console.WriteLine(n);
the type of n is inferred to be int, the element type of numbers.
Share with your friends: |