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.
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
(condition)
statement(s)
else
statement(s)
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):
bool isZero;
if (i == 0)
{
isZero = true;
Console.WriteLine("i is Zero");
}
else
{
isZero = false;
Console.WriteLine("i is Non-zero");
}
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:
using
System;
class MainEntryPoint
{
static void Main(string[] args)
{
Console.WriteLine("Type in a string");
string input;
input = Console.ReadLine();
if (input == "")
{
Console.WriteLine("You typed in an empty string");
}
else if (input.Length < 5)
{
Console.WriteLine("The string had less than 5
characters");
}
else if (input.Length < 10)
{
Console.WriteLine("The string had at least 5 but less
than 10
characters");
}
Console.WriteLine("The string was " + input);
}
}
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:
if (i == 0)
Console.WriteLine("i is Zero"); // This will only execute if i == 0
Console.WriteLine("i can be anything"); // Will execute whatever the
// value of i
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 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:
if (DoSomething() != 0)
{
// Non-zero value returned
}
else
{
// Returned zero
}
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...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:
switch (integerA)
{
case 1:
Console.WriteLine("integerA =1");
break;
case 2:
Console.WriteLine("integerA =2");
break;
case 3:
Console.WriteLine("integerA =3");
break;
default:
Console.WriteLine("integerA is not 1,2, or 3");
break;
}
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:
// assume country and language are of type string
switch(country)
{
case "America":
CallAmericanOnlyMethod();
goto case "Britain";
case "France":
language = "French";
break;
case "Britain":
language = "English";
break;
}
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):
switch(country)
{
case "au":
case "uk":
case "us":
language = "English";
break;
case "at":
case "de":
language = "German";
break;
}
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:
// assume country is of type string
const string england = "uk";
const string britain = "uk";
switch(country)
{
case england:
case britain: //
this will cause a compilation error
language = "English";
break;
The previous code also shows another
way in which the switch statement is different in C# from C++: In C#, you are
allowed to use a string as the variable being tested.
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++.
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
for
(initializer; condition; iterator)
statement(s)
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 pre-test
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:
for (int i = 0; i < 100; i = i+1) // this is equivalent to
// For i = 0 To 99 in VB.
{
Console.WriteLine(i);
}
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++:
for (int i = 0; i < 100; 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.
using
System;
class MainEntryPoint
{
static void Main(string[] args)
{
// This loop iterates through rows...
for (int i = 0; i < 100; i+=10)
{
// This loop iterates through columns...
for (int j = i; j < i + 10; j++)
{
Console.Write("
" + j);
}
Console.WriteLine();
}
}
}
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 re-declared 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:
0 1 2
3 4
5 6 7
8 9
10 11
12 13 14
15 16 17
18 19
20 21
22 23 24
25 26 27
28 29
30 31
32 33 34
35 36 37
38 39
40 41
42 43 44
45 46 47
48 49
50 51
52 53 54
55 56 57
58 59
60 61
62 63 64
65 66 67
68 69
70 71
72 73 74
75 76 77
78 79
80 81
82 83 84
85 86 87
88 89
90 91 92 93
94 95 96
97 98 99
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 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 pre-test loop. The syntax is similar, but while loops take
only one expression:
while(condition)
statement(s);
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:
bool condition = false;
while (!condition)
{
// This loop spins until the condition is true
DoSomeWork();
condition = CheckCondition(); // assume CheckCondition() returns a bool
}
All of C#'s looping mechanisms,
including the while loop, can forego 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 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:
bool condition;
do
{
// this loop will at least execute once, even if Condition
is false
MustBeCalledAtLeastOnce();
condition = CheckCondition();
} while (condition);
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 (bor- rowed from Visual Basic), and a very welcome one at that.
The foreach loop allows you to
iterate through each item in a collection.
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:
foreach (int temp in arrayOfInts)
{
Console.WriteLine(temp);
}
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:
foreach (int temp in arrayOfInts)
{
temp++;
Console.WriteLine(temp);
}
If you need to iterate through the
items in a collection and change their values, you will need to use a for loop
instead.
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 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):
goto Label1;
Console.WriteLine("This won't be
Label1:
Console.WriteLine("Continuing execution from
here");
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.
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.
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 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
execution will restart at the beginning of the next iteration of the loop,
rather than outside the loop altogether.
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.