It is possible to alter the execution path of a loop. In fact, with jump statements, it is possible to escape out of the loop or to skip the remaining portion of an iteration and begin with the next iteration, even when the loop condition remains true. This section considers some of the ways to jump the execution path from one location to another.
To escape out of a loop or a switch statement, C# uses a break statement. Whenever the break statement is encountered, control immediately leaves the loop or switch. Listing 4.51 examines the foreach loop from the tic-tac-toe program and Output 4.24 shows the output.
Listing 4.51 uses a break statement when a player holds a winning position. The break statement forces its enclosing loop (or a switch statement) to cease execution, and control moves to the next line outside the loop. For this listing, if the bit comparison returns true (if the board holds a winning position), the break statement causes control to jump and display the winner.
The full tic-tac-toe listing uses the bitwise operators to determine which player wins the game. First, the code saves the positions of each player into a bitmap called playerPositions. (It uses an array with two items so that the positions for both players can be saved.)
To begin, both playerPositions are 0. As each player moves, the bit corresponding to the move is set. If, for example, the player selects cell 3, shifter is set to 3 – 1. The code subtracts 1 because C# is zero based and you need to adjust for 0 as the first position instead of 1. Next, the code sets position, the bit corresponding to cell 3, using the shift operator 000000000000001 << shifter, where shifter now has a value of 2. Lastly, it sets playerPositions for the current player (subtracting 1 again to shift to zero based) to 0000000000000100. Listing 4.52 uses |= so that previous moves are combined with the current move.
Later in the program, you can iterate over each mask corresponding to winning positions on the board to determine whether the current player has a winning position, as shown in Listing 4.51.
You might have a block containing a series of statements within a loop. If you determine that some conditions warrant executing only a portion of these statements for some iterations, you can use the continue statement to jump to the end of the current iteration and begin the next iteration. The continue statement exits the current iteration (regardless of whether additional statements remain) and jumps to the loop condition. At that point, if the loop conditional is still true, the loop will continue execution.
Listing 4.53 uses the continue statement so that only the letters of the domain portion of an email are displayed. Output 4.25 shows the results of Listing 4.53.
In Listing 4.53, if you are not yet inside the domain portion of the email address, you can use a continue statement to move control to the end of the loop, and process the next character in the email address.
You can almost always use an if statement in place of a continue statement, and this format is usually more readable. The problem with the continue statement is that it provides multiple flows of control within a single iteration, which compromises readability. In Listing 4.54, the example in Listing 4.53 has been rewritten by replacing the continue statement with the if/else construct to demonstrate a more readable version that does not use the continue statement.
Early programming languages lacked the sophisticated “structured” control flows that modern languages such as C# have as a matter of course. Instead, they relied on simple conditional branching (if) and unconditional branching (goto) statements for most of their control flow needs. The resultant programs were often hard to understand. The continued existence of a goto statement within C# seems like an anachronism to many experienced programmers. However, C# supports goto, and it is the only method for supporting fall-through within a switch statement. In Listing 4.55, if the /out option is set, code execution jumps to the default case using the goto statement, and similarly for /f. Output 4.26 provides an example of the program executing.
To branch to a switch section label other than the default label, you can use the syntax goto case constant;, where constant is the constant associated with the case label you wish to branch to. To branch to a statement that is not associated with a switch section, precede the target statement with any identifier followed by a colon; you can then use that identifier with the goto statement. For example, you could have a labeled statement myLabel : Console.WriteLine();. The statement goto myLabel; would then branch to the labeled statement. Fortunately, C# prevents you from using goto to branch outside of the goto statements scope; instead, goto may be used only to branch within the immediate code block or to an enclosing code block. By enforcing these restrictions, C# avoids most of the serious goto abuses possible in other languages.
In spite of the improvements, use of goto is generally considered to be inelegant, difficult to understand, and symptomatic of poorly structured code. If you need to execute a section of code multiple times or under different circumstances, either use a loop or extract code to a method of its own.