Jump statements unconditionally transfer control.
jump-statement:
break-statement
continue-statement
goto-statement
return-statement
throw-statement
The location to which a jump statement transfers control is called the
target of the jump statement.
When a jump statement occurs within a block, and the target of that jump
statement is outside that block, the
jump statement is said to exit the block. While a jump statement may
transfer control out of a block, it can
never transfer control into a block.
Execution of jump statements is complicated by the presence of intervening
try statements. In the absence
of such try statements, a jump statement unconditionally transfers control
from the jump statement to its
target. In the presence of such intervening try statements, execution is
more complex. If the jump statement
exits one or more try blocks with associated finally blocks, control is
initially transferred to the
finally block of the innermost try statement. When and if control reaches
the end point of a finally
block, control is transferred to the finally block of the next enclosing
try statement. This process is
repeated until the finally blocks of all intervening try statements have
been executed.
[Example: In the example
Chapter 15 Statements
191
using System;
class Test
{
static void Main() {
while (true) {
try {
try {
Console.WriteLine("Before break");
break;
}
finally {
Console.WriteLine("Innermost finally block");
}
}
finally {
Console.WriteLine("Outermost finally block");
}
}
Console.WriteLine("After break");
}
}
the finally blocks associated with two try statements are executed before
control is transferred to the target
of the jump statement.
The output produced is as follows:
Before break
Innermost finally block
Outermost finally block
After break
end example]
15.9.1 The break statement
The break statement exits the nearest enclosing switch, while, do, for, or
foreach statement.
break-statement:
break ;
The target of a break statement is the end point of the nearest enclosing
switch, while, do, for, or
foreach statement. If a break statement is not enclosed by a switch, while,
do, for, or foreach
statement, a compile-time error occurs.
When multiple switch, while, do, for, or foreach statements are nested
within each other, a break
statement applies only to the innermost statement. To transfer control
across multiple nesting levels, a goto
statement (§15.9.3) must be used.
A break statement cannot exit a finally block (§15.10). When a break
statement occurs within a
finally block, the target of the break statement must be within the same
finally block; otherwise a
compile-time error occurs.
A break statement is executed as follows:
? If the break statement exits one or more try blocks with associated
finally blocks, control is
initially transferred to the finally block of the innermost try statement.
When and if control reaches
the end point of a finally block, control is transferred to the finally
block of the next enclosing try
statement. This process is repeated until the finally blocks of all
intervening try statements have
been executed.
? Control is transferred to the target of the break statement.
Because a break statement unconditionally transfers control elsewhere, the
end point of a break statement
is never reachable.
C# LANGUAGE SPECIFICATION
192
15.9.2 The continue statement
The continue statement starts a new iteration of the nearest enclosing
while, do, for, or foreach
statement.
continue-statement:
continue ;
The target of a continue statement is the end point of the embedded
statement of the nearest enclosing
while, do, for, or foreach statement. If a continue statement is not
enclosed by a while, do, for, or
foreach statement, a compile-time error occurs.
When multiple while, do, for, or foreach statements are nested within each
other, a continue
statement applies only to the innermost statement. To transfer control
across multiple nesting levels, a goto
statement (§15.9.3) must be used.
A continue statement cannot exit a finally block (§15.10). When a continue
statement occurs within
a finally block, the target of the continue statement must be within the
same finally block;
otherwise a compile-time error occurs.
A continue statement is executed as follows:
? If the continue statement exits one or more try blocks with associated
finally blocks, control is
initially transferred to the finally block of the innermost try statement.
When and if control reaches
the end point of a finally block, control is transferred to the finally
block of the next enclosing try
statement. This process is repeated until the finally blocks of all
intervening try statements have
been executed.
? Control is transferred to the target of the continue statement.
Because a continue statement unconditionally transfers control elsewhere,
the end point of a continue
statement is never reachable.
15.9.3 The goto statement
The goto statement transfers control to a statement that is marked by a
label.
goto-statement:
goto identifier ;
goto case constant-expression ;
goto default ;
The target of a goto identifier statement is the labeled statement with the
given label. If a label with the
given name does not exist in the current function member, or if the goto
statement is not within the scope of
the label, a compile-time error occurs. [Note: This rule permits the use of
a goto statement to transfer
control out of a nested scope, but not into a nested scope. In the example
using System;
class Test
{
static void Main(string[] args) {
string[,] table = {
{"red", "blue", "green"},
{"Monday", "Wednesday", "Friday"}
};
foreach (string str in args) {
int row, colm;
for (row = 0; row <= 1; ++row)
for (colm = 0; colm <= 2; ++colm)
if (str == table[row,colm])
goto done;
Chapter 15 Statements
193
Console.WriteLine("{0} not found", str);
continue;
done:
Console.WriteLine("Found {0} at [{1}][{2}]", str, row, colm);
}
}
}
a goto statement is used to transfer control out of a nested scope. end
note]
The target of a goto case statement is the statement list in the
immediately enclosing switch statement
(§15.7.2) which contains a case label with the given constant value. If
the goto case statement is not
enclosed by a switch statement, if the constant-expression is not
implicitly convertible (§13.1) to the
governing type of the nearest enclosing switch statement, or if the nearest
enclosing switch statement
does not contain a case label with the given constant value, a compile-time
error occurs.
The target of a goto default statement is the statement list in the
immediately enclosing switch statement
(§15.7.2), which contains a default label. If the goto default statement
is not enclosed by a switch
statement, or if the nearest enclosing switch statement does not contain a
default label, a compile-time
error occurs.
A goto statement cannot exit a finally block (§15.10). When a goto
statement occurs within a
finally block, the target of the goto statement must be within the same
finally block, or otherwise a
compile-time error occurs.
A goto statement is executed as follows:
? If the goto statement exits one or more try blocks with associated
finally blocks, control is initially
transferred to the finally block of the innermost try statement. When and
if control reaches the end
point of a finally block, control is transferred to the finally block of
the next enclosing try
statement. This process is repeated until the finally blocks of all
intervening try statements have
been executed.
? Control is transferred to the target of the goto statement.
Because a goto statement unconditionally transfers control elsewhere, the
end point of a goto statement is
never reachable.
15.9.4 The return statement
The return statement returns control to the caller of the function member
in which the return statement
appears.
return-statement:
return expressionopt ;
A return statement with no expression can be used only in a function member
that does not compute a
value; that is, a method with the return type void, the set accessor of a
property or indexer, the add and
remove accessors of an event, an instance constructor, static constructor,
or a destructor.
A return statement with an expression can only be used in a function member
that computes a value, that
is, a method with a non-void return type, the get accessor of a property or
indexer, or a user-defined
operator. An implicit conversion (§13.1) must exist from the type of the
expression to the return type of the
containing function member.
It is a compile-time error for a return statement to appear in a finally
block (§15.10).
A return statement is executed as follows:
? If the return statement specifies an expression, the expression is
evaluated and the resulting value is
converted to the return type of the containing function member by an
implicit conversion. The result of
the conversion becomes the value returned to the caller.
C# LANGUAGE SPECIFICATION
194
? If the return statement is enclosed by one or more try blocks with
associated finally blocks,
control is initially transferred to the finally block of the innermost try
statement. When and if
control reaches the end point of a finally block, control is transferred to
the finally block of the
next enclosing try statement. This process is repeated until the finally
blocks of all enclosing try
statements have been executed.
? Control is returned to the caller of the containing function member.
Because a return statement unconditionally transfers control elsewhere, the
end point of a return
statement is never reachable.
15.9.5 The throw statement
The throw statement throws an exception.
throw-statement:
throw expressionopt ;
A throw statement with an expression throws the value produced by
evaluating the expression. The
expression must denote a value of the class type System.Exception or of a
class type that derives from
System.Exception. If evaluation of the expression produces null, a
System.NullReferenceException is thrown instead.
A throw statement with no expression can be used only in a catch block, in
which case, that statement rethrows
the exception that is currently being handled by that catch block.
Because a throw statement unconditionally transfers control elsewhere, the
end point of a throw statement
is never reachable.
When an exception is thrown, control is transferred to the first catch
clause in an enclosing try statement
that can handle the exception. The process that takes place from the point
of the exception being thrown to
the point of transferring control to a suitable exception handler is known
as exception propagation.
Propagation of an exception consists of repeatedly evaluating the following
steps until a catch clause that
matches the exception is found. In this description, the throw point is
initially the location at which the
exception is thrown.
? In the current function member, each try statement that encloses the
throw point is examined. For each
statement S, starting with the innermost try statement and ending with the
outermost try statement, the
following steps are evaluated:
If the try block of S encloses the throw point and if S has one or more
catch clauses, the catch clauses
are examined in order of appearance to locate a suitable handler for the
exception. The first catch clause
that specifies the exception type or a base type of the exception type is
considered a match. A general catch
(§15.10) clause is considered a match for any exception type. If a
matching catch clause is located, the
exception propagation is completed by transferring control to the block of
that catch clause.
Otherwise, if the try block or a catch block of S encloses the throw point
and if S has a finally block,
control is transferred to the finally block. If the finally block throws
another exception, processing of
the current exception is terminated. Otherwise, when control reaches the
end point of the finally block,
processing of the current exception is continued.
? If an exception handler was not located in the current function member
invocation, the function member
invocation is terminated. The steps above are then repeated for the caller
of the function member with a
throw point corresponding to the statement from which the function member
was invoked.
? If the exception processing terminates all function member invocations in
the current thread, indicating
that the thread has no handler for the exception, then the thread is itself
terminated. The impact of such
termination is implementation-defined.