Iteration statements repeatedly execute an embedded statement.
iteration-statement:
while-statement
do-statement
for-statement
foreach-statement
15.8.1 The while statement
The while statement conditionally executes an embedded statement zero or
more times.
Chapter 15 Statements
187
while-statement:
while ( boolean-expression ) embedded-statement
A while statement is executed as follows:
? The boolean-expression (§14.16) 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 (§15.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 (§15.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.
15.8.2 The 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 (§14.16) 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 (§15.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 (§15.9.2) may be used to transfer control to the end
point of the embedded statement
(thus performing another iteration of the do 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.
15.8.3 The 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
C# LANGUAGE SPECIFICATION
188
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 (§15.5.1) or a list of statementexpressions
(§15.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 (§14.16).
The for-iterator, if present, consists of a list of statement-expressions (§
15.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 (§15.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 (§15.9.2) may be used to transfer control to the end
point of the embedded statement
(thus executing another iteration of the for statement).
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.
15.8.4 The foreach statement
The foreach statement enumerates the elements of a collection, executing an
embedded statement for each
element of the collection.
foreach-statement:
foreach ( type identifier in expression ) embedded-statement
Chapter 15 Statements
189
The type and identifier of a foreach statement declare the iteration
variable of the statement. 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 type of the expression of a foreach statement must be a collection type
(as defined below), and an
explicit conversion (§13.2) must exist from the element type of the
collection to the type of the iteration
variable. If expression has the value null, a System.NullReferenceException
is thrown.
A type C is said to be a collection type if it implements the
System.Collections.IEnumerable
interface or implements the collection pattern by meeting all of the
following criteria:
? C contains a public instance method with the signature GetEnumerator(),
that returns a struct-type,
class-type, or interface-type, which is called E in the following text.
? E contains a public instance method with the signature MoveNext() and the
return type bool.
? E contains a public instance property named Current that permits reading
the current value. The type
of this property is said to be the element type of the collection type.
A type that implements IEnumerable is also a collection type, even if it
doesn’t satisfy the conditions
above. (This is possible if it implements IEnumerable via explicit
interface member implementations.)
The System.Array type (§19.1.1) is a collection type, and since all array
types derive from
System.Array, any array type expression is permitted in a foreach
statement. 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 multidimensional
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.
A foreach statement of the form:
foreach (ElementType element in collection) statement
corresponds to one of two possible expansions:
? If the collection expression is of a type that implements the collection
pattern (as defined above), the
expansion of the foreach statement is:
Enumerator enumerator = (collection).GetEnumerator();
try {
while (enumerator.MoveNext()) {
ElementType element = (ElementType)enumerator.Current;
statement;
}
}
finally {
IDisposable disposable = enumerator as System.IDisposable;
if (disposable != null) disposable.Dispose();
}
[Note: Significant optimizations of the above are often easily available.
If the type E implements
System.IDisposable, then the expression (enumerator as System.IDisposable)
will always
be non-null and the implementation can safely substitute a simple
conversion for a possibly more
expensive type test. Conversely, if the type E is sealed and does not
implement
System.IDisposable, then the expression (enumerator as System.IDisposable)
will
always evaluate to null. In this case, the implementation can safely
optimize away the entire finally
clause. end note]
? Otherwise; the collection expression is of a type that implements
System.Collections.IEnumerable, and the expansion of the foreach statement
is:
C# LANGUAGE SPECIFICATION
190
IEnumerator enumerator =
((System.IEnumerable)(collection)).GetEnumerator();
try {
while (enumerator.MoveNext()) {
ElementType element = (ElementType)enumerator.Current;
statement;
}
}
finally {
IDisposable disposable = enumerator as System.IDisposable;
if (disposable != null) disposable.Dispose();
}
In either expansion, the enumerator variable is a temporary variable that
is inaccessible in, and invisible
to, the embedded statement, and the element variable is read-only in the
embedded statement.
[Example: 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
end example]