Flow Control
This section looks at the real nuts and bolts
of the language: the statements that allow you to control the
flow of your program rather than executing
every line of code in the order it appears in the program.
Conditional Statements
Conditional statements allow you to branch
your code depending on whether certain conditions are met or on the
value of an expression. C# has two constructs for branching code -
the if statement, which allows you to
test whether a specific condition is met, and the switch statement, which allows you to compare an
expression with a number of different values.
The
if Statement
For conditional branching, C# inherits the C
and C++ if...else construct. The syntax
should be fairly intuitive for anyone who has done any programming
with a procedural language:
If more than one statement is to be executed as
part of either condition, these statements will need to be joined
together into a block using curly braces ({ ...
}). (This also applies to other C# constructs where
statements can be joined into a block, such as the for and while loops):
The syntax here is similar to C++ and Java but once
again different from Visual Basic. Visual Basic developers should
note that C# does not have any statement corresponding to Visual
Basic’s EndIf. Instead, the rule is that
each clause of an if contains just one
statement. If you need more than one statement, as in the preceding
example, you should enclose the statements in braces, which will
cause the whole group of statements to be treated as a single block
statement.
If you want to, you can use an if statement without a final else statement. You can also combine else if clauses to test
for multiple conditions:
There is no limit to how many else if’s you can add to an if clause.
You’ll notice that the previous example declares a
string variable called input, gets the
user to enter text at the command line, feeds this into
input, and then tests the length of this
string variable. The code also shows how easy string manipulation
can be in C#. To find the length of input, for example, use input.Length.
One point to note about if is that you don’t need to use the braces if
there’s only one statement in the conditional branch:
However, for consistency, many programmers prefer
to use curly braces whenever they use an if statement.
The if statements
presented also illustrate some of the C# operators that compare
values. Note in particular that, like C++ and Java, C# uses
== to compare variables for equality. Do
not use = for this purpose. A single
= is used to assign values.
In C#, the expression in the if clause must evaluate to a Boolean. C++
programmers should be particularly aware of this; unlike in C++, it
is not possible to test an integer (returned from a function, say)
directly. In C#, you have to convert the integer that is returned
to a Boolean true or false, for example, by comparing the value with zero
or with null:
This restriction is there in order to prevent some
common types of runtime bugs that occur in C++. In particular, in
C++ it was common to mistype = when
== was intended, resulting in
unintentional assignments. In C# this will normally result in a
compile-time error, because unless you are working with
bool values, = will not return a bool.
The
switch Statement
The switch...case
statement is good for selecting one branch of execution from a set
of mutually exclusive ones. It will be familiar to C++ and Java
programmers and is similar to the Select
Case statement in Visual Basic.
It takes the form of a switch argument followed by a series of case clauses. When the expression in the
switch argument evaluates to one of the
values beside a case clause, the code
immediately following the case clause
executes. This is one example where you don’t need to use curly
braces to join statements into blocks; instead, you mark the end of
the code for each case using the break
statement. You can also include a default case in the switch statement, which will execute if the
expression evaluates to none of the other cases. The following
switch statement tests the value of the
integerA variable:
Note that the case values must be constant
expressions; variables are not permitted.
Though the switch...case
statement should be familiar to C and C++ programmers, C#’s
switch...case is a bit safer than its
C++ equivalent. Specifically, it prohibits fall-through conditions
in almost all cases. This means that if a case clause is fired early on in the block, later
clauses cannot be fired unless you use a goto statement to mark that you want them fired,
too. The compiler enforces this restriction by flagging every
case clause that is not equipped with a
break statement as an error similar to
this:
Although it is true that fall-through behavior is
desirable in a limited number of situations, in the vast majority
of cases, it is unintended and results in a logical error that’s
hard to spot. Isn’t it better to code for the norm rather than for
the exception?
By getting creative with goto statements (which C# does support), however,
you can duplicate fall-through functionality in your switch...cases. However, if you find yourself really
wanting to, you probably should reconsider your approach. The
following code illustrates both how to use goto to simulate fall-through, and how messy the
resultant code can get:
There is one exception to the no-fall-through rule,
however, in that you can fall through from one case to the next if
that case is empty. This allows you to treat two or more cases in
an identical way (without the need for goto statements):
One intriguing point about the switch statement in C# is that the order of the
cases doesn’t matter - you can even put the default case first! As a result, no two cases can be
the same. This includes different constants that have the same
value, so you can’t, for example, do this:
The previous code also shows another way in
which the switch statement is different
in C# compared to C++: In C#, you are allowed to use a string as
the variable being tested.
Loops
C# provides four different loops
(for, while,
do...while, and foreach) that allow you to execute a block of code
repeatedly until a certain condition is met. The for, while, and
do...while loops are essentially
identical to those encountered in C++.
The
for Loop
C# for loops
provide a mechanism for iterating through a loop where you test
whether a particular condition holds before you perform another
iteration. The syntax is
where
-
The initializer is the expression evaluated
before the first loop is executed (usually initializing a local
variable as a loop counter).
-
The condition is the expression checked
before each new iteration of the loop (this must evaluate to
true for another iteration to be
performed).
-
The iterator is an expression evaluated after
each iteration (usually incrementing the loop counter). The
iterations end when the condition evaluates to false.
The for loop is a
so-called pretest loop, because the loop condition is evaluated
before the loop statements are executed, and so the contents of the
loop won’t be executed at all if the loop condition is false.
The for loop is
excellent for repeating a statement or a block of statements for a
predetermined number of times. The following example is typical of
the use of a for loop. The following
code will write out all the integers from 0 to 99:
Here, you declare an int
called i and initialize it to zero. This
will be used as the loop counter. You then immediately test whether
it is less than 100. Because this condition evaluates to
true, you execute the code in the loop,
displaying the value 0. You then increment the counter by one, and
walk through the process again. Looping ends when i reaches 100.
Actually, the way the preceding loop is written
isn’t quite how you would normally write it. C# has a shorthand for
adding 1 to a variable, so instead of i = i +
1, you can simply write i++:
C# for loop syntax is
far more powerful than the Visual Basic For...Next loop, because the iterator can be any
statement. In Visual Basic, all you can do is add or subtract some
number from the loop control variable. In C# you can do anything;
for example, you can multiply the loop control variable by 2.
It’s not unusual to nest for loops so that an inner loop executes once
completely for each iteration of an outer loop. This scheme is
typically employed to loop through every element in a rectangular
multidimensional array. The outermost loop loops through every row,
and the inner loop loops through every . column in a particular row. The following code
displays rows of numbers. It also uses another Console method, Console.Write(), which does the same as Console.WriteLine() but doesn’t send a carriage
return to the output.
Although j is an
integer, it will be automatically converted to a string so that the
concatenation can take place. C++ developers will note that this is
far easier than string handling ever was in C++; for Visual Basic
developers this is familiar ground.
C programmers should take note of one particular
feature of the preceding example. The counter variable in the
innermost loop is effectively redeclared with each successive
iteration of the outer loop. This syntax is legal not only in C#
but in C++ as well.
The preceding sample results in this output:
csc NumberTable.cs
Although it is technically possible to
evaluate something other than a counter variable in a for loop’s test condition, it is certainly not
typical. It is also possible to omit one (or even all) of the
expressions in the for loop. In such
situations, however, you should consider using the while loop.
The
while Loop
The while loop is
identical to the while loop in C++ and
Java, and the While...Wend loop in
Visual Basic. Like the for loop,
while is a pretest loop. The syntax is
similar, but while loops take only one
expression:
Unlike the for loop, the
while loop is most often used to repeat
a statement or a block of statements for a number of times that is
not known before the loop begins. Usually, a statement inside the
while loop’s body will set a Boolean
flag to false on a certain iteration,
triggering the end of the loop, as in the following example:
All of C#’s looping mechanisms, including the
while loop, can forgo the curly braces
that follow them if they intend to repeat just a single statement
and not a block of statements. Again, many programmers consider it
good practice to use braces all of the time.
The
do . . . while Loop
The do...while
loop is the post-test version of the while loop. It does the same thing with the same
syntax as do...while in C++ and Java,
and the same thing as Loop...While in
Visual Basic. This means that the loop’s test condition is
evaluated after the body of the loop has been executed.
Consequently, do...while loops are
useful for situations in which a block of statements must be
executed at least one time, as in this example:
The
foreach Loop
The foreach loop
is the final C# looping mechanism that we discuss. Whereas the
other looping mechanisms were present in the earliest versions of C
and C++, the foreach statement is a new
addition (borrowed from Visual Basic), and a very welcome one at
that.
The foreach loop allows
you to iterate through each item in a collection. For the time
being we won’t worry about exactly what a collection is - it is
explained fully in Chapter 10, “Collections.” For now, we
will just say that it is an object that contains other objects.
Technically, to count as a collection, it must support an interface
called IEnumerable. Examples of
collections include C# arrays, the collection classes in the
System.Collection namespaces, and
user-defined collection classes. You can get an idea of the syntax
of foreach from the following code, if
you assume that arrayOfInts is
(unsurprisingly) an array if ints:
Here, foreach steps
through the array one element at a time. With each element, it
places the value of the element in the int variable called temp
and then performs an iteration of the loop.
An important point to note with foreach is that you can’t change the value of the
item in the collection (temp in the
preceding code), so code such as the following will not
compile:
If you need to iterate through the items in a
collection and change their values, you will need to use a
for loop instead.
Jump Statements
C# provides a number of statements that allow
you to jump immediately to another line in the program. The first
of these is, of course, the notorious goto statement.
The goto Statement
The goto statement
allows you to jump directly to another specified line in the
program, indicated by a label (this is just
an identifier followed by a colon):
A couple of restrictions are involved with
goto. You can’t jump into a block of
code such as a for loop, you can’t jump
out of a class, and you can’t exit a finally block after try...catch blocks (Chapter 13, “Errors and
Exceptions,” looks at exception handling with try...catch...finally).
The reputation of the goto statement probably precedes it, and in most
circumstances, its use is sternly frowned upon. In general, it
certainly doesn’t conform to good object-oriented programming
practice.
However, there is one place where it is quite
handy: jumping between cases in a switch
statement, particularly because C#’s switch is so strict on fall-through. You saw the
syntax for this earlier in this chapter.
The break Statement
You have already met the break statement briefly - when you used it to exit
from a case in a switch statement. In
fact, break can also be used to exit
from for, foreach, while, or
do...while loops too. Control will
switch to the statement immediately after the end of the loop.
If the statement occurs in a nested loop,
control will switch to the end of the innermost loop. If the break
occurs outside of a switch statement or
a loop, a compile-time error will occur.
The continue Statement
The continue
statement is similar to break, and must
also be used within a for, foreach, while, or
do...while loop. However, it exits only
from the current iteration of the loop, meaning that execution will
restart at the beginning of the next iteration of the loop, rather
than outside the loop altogether.
The return Statement
The return
statement is used to exit a method of a class, returning control to
the caller of the method. If the method has a return type,
return must return a value of this type;
otherwise if the method returns void,
you should use return without an
expression.
|