Team LiB   Previous Section   Next Section

6.2 Conditional Branching Statements

While methods branch unconditionally, often you will want to branch within a method depending on a condition that you evaluate while the program is running. This is known as conditional branching. Conditional branching statements allow you to write logic such as "If you are over 25 years old, then you may rent a car."

C# provides a number of constructs that allow you to write conditional branches into your programs; these constructs are described in the following sections.

6.2.1 if Statements

The simplest branching statement is if. An if statement says, "if a particular condition is true, then execute the statement; otherwise skip it." The condition is a Boolean expression. An expression is a statement that evaluates to a value, and a Boolean expression evaluates to either true or false.

The formal description of an if statement is:

if  (expression )
   Statement1 

This is the kind of description of the if statement you are likely to find in your compiler documentation. It shows you that the if statement takes an expression (a statement that returns a value) in parentheses, and executes Statement1 if the expression evaluates true. Note that Statement1 can actually be a block of statements within braces, as illustrated in Example 6-2.

Anywhere in C# that you are expected to provide a statement, you can instead provide a block of statements within braces. (See the sidebar Brace Styles later in this chapter.)

Example 6-2. The if statement
using System;

namespace Branching
{
   class Test
   {
      static void Main()
      {
            int valueOne = 10;
            int valueTwo = 20;
            int valueThree = 30;

            Console.WriteLine("Testing valueOne against valueTwo...");
            if ( valueOne > valueTwo )
            {
                Console.WriteLine(
                "ValueOne: {0} larger than ValueTwo: {1}", 
                valueOne, valueTwo);
            }

            Console.WriteLine("Testing valueThree against valueTwo...");
            if ( valueThree > valueTwo )
            {
                Console.WriteLine(
                    "ValueThree: {0} larger than ValueTwo: {1}", 
                    valueThree, valueTwo);
            }   // end if

      }         // end Main
   }            // end class
}               // end namespace

In this simple program, you declare three variables, valueOne, valueTwo, and valueThree, with the values 10, 20, and 30, respectively. In the first if statement, you test whether valueOne is greater than valueTwo.

if ( valueOne > valueTwo )
{
    Console.WriteLine(
    "ValueOne: {0} larger than ValueTwo: {1}", 
    valueOne, valueTwo);
}

Because valueOne (10) is less than valueTwo (20), this if statement fails (the condition returns false), and thus the body of the if statement (the statements within the braces) doesn't execute.

The test for greater-than uses the greater-than operator (>), which is discussed in detail in Chapter 7.

You then test whether valueThree is greater than valueTwo:

if ( valueThree > valueTwo )
{
    Console.WriteLine(
        "ValueThree: {0} larger than ValueTwo: {1}", 
        valueThree, valueTwo);
}

Since valueThree (30) is greater than valueTwo (20), the test returns true, and thus the statement executes. The statement in this case is the block in which you call the WriteLine() method, shown in bold. The output reflects that the first if fails but the second succeeds:

Testing valueOne against valueTwo...
Testing valueThree against valueTwo...
ValueThree: 30 larger than ValueTwo: 20

6.2.2 Single Statement if Blocks

Notice that the if statement blocks shown in Example 6-2 each contain only a single statement, one call to WriteLine(). In such cases, you can leave out the braces enclosing the if block. Thus you might rewrite Example 6-2 as shown in Example 6-3.

Example 6-3. Single statements with if
using System;

namespace Branching
{
    class Test
    {
        static void Main()
        {
            int valueOne = 10;
            int valueTwo = 20;
            int valueThree = 30;

            Console.WriteLine("Testing valueOne against valueTwo...");
            if ( valueOne > valueTwo )
                Console.WriteLine(
                "ValueOne: {0} larger than ValueTwo: {1}", 
                valueOne, valueTwo);

            Console.WriteLine("Testing valueThree against valueTwo...");
            if ( valueThree > valueTwo )
                Console.WriteLine(
                    "ValueThree: {0} larger than ValueTwo: {1}", 
                    valueThree, valueTwo);

        }       // end Main
    }           // end class
}               // end namespace

It is generally a good idea, however, to use the braces even when your if block has only a single statement. There are two reasons for this advice. First, the code is somewhat easier to read and understand with the braces. Code that is easier to read is easier to maintain.

When programmers talk about maintaining code, they mean either adding to the code as requirements change or fixing the code as bugs arise.

The second reason for using braces is to avoid a common error: adding a second statement to the if and forgetting to add the braces. Consider the code shown in Example 6-4. The programmer has changed the value of valueThree to 10 and added a second statement to the second if block, as shown in bold.

Example 6-4. Adding a second statement to if
using System;

namespace Branching
{
    class Test
    {
        static void Main()
        {
            int valueOne = 10;
            int valueTwo = 20;
            int valueThree = 10;

            Console.WriteLine("Testing valueOne against valueTwo...");
            if ( valueOne > valueTwo )
                Console.WriteLine(
                "ValueOne: {0} larger than ValueTwo: {1}", 
                valueOne, valueTwo);

            Console.WriteLine("Testing valueThree against valueTwo...");
            if ( valueThree > valueTwo )
                Console.WriteLine(
                    "ValueThree: {0} larger than ValueTwo: {1}", 
                    valueThree, valueTwo);
                Console.WriteLine("Good thing you tested again!");

        }       // end Main
    }           // end class
}               // end namespace

Now, before reading any further, review the code and decide for yourself what the output should be. Don't cheat by looking past this paragraph. Then, when you think you know what the output will be, take a look at this:

Testing valueOne against valueTwo...
Testing valueThree against valueTwo...
Good thing you tested again!

Were you surprised?

The programmer was fooled by the lack of braces and the indentation. Remember that indentation is whitespace and is ignored by the compiler. From the perspective of the programmer, the second statement ("Good thing . . . ") is part of the if block:

if ( valueThree > valueTwo )
     Console.WriteLine(
         "ValueThree: {0} larger than ValueTwo: {1}", 
         valueThree, valueTwo);
     Console.WriteLine("Good thing you tested again!");

The compiler, however, considers only the first statement after the if test to be part of the if statement. The second statement is not part of the if statement. To the compiler, the if statement looks like this:

if ( valueThree > valueTwo )
     Console.WriteLine(
         "ValueThree: {0} larger than ValueTwo: {1}", 
         valueThree, valueTwo);

Console.WriteLine("Good thing you tested again!");

If you want the second statement to be part of the if statement, you must use braces, as in the following:

if ( valueThree > valueTwo )
{
    Console.WriteLine(
        "ValueThree: {0} larger than ValueTwo: {1}", 
        valueThree, valueTwo);
    Console.WriteLine("Good thing you tested again!");
}

Because of this potential for confusion, many C# programmers use braces with every if statement, even if the statement is only one line.

Brace Styles

There are many ways you can form braces around an if statement (and around other blocks of code), but most C# programmers will use one of three styles:

if (condition)
{
   // statement
}

if (condition)
   {
   // statement 
   }

if (condition){
  // statement
}

The first style, used throughout this book, is to put the braces under the keyword if and to indent the contents of the if block. The second style, not very popular any more, is to indent the braces with the contents of the if block. The third style is to put the opening brace on the same line as the if statement and the closing brace under the if statement.

The third style is called K&R style, after Kernighan and Ritchie, the authors of the seminal book The C Programming Language (Prentice Hall). Their book was so influential that many programmers feel a strong commitment to this style of braces. While it does save room in a book, the K&R style is a bit less clear, and so this book will use the first style.

6.2.3 if . . . else Statements

Often, you will find that you want to take one set of actions when the condition tests true and a different set of actions when the condition tests false. This allows you to write logic such as "If you are over 25 years old, then you may rent a car; otherwise, you must take the train."

The otherwise portion of the logic is executed in the else statement. For example, you can modify Example 6-2 to print an appropriate message whether or not valueOne is greater than valueTwo, as shown in Example 6-5.

Example 6-5. The else statement
using System;

namespace Branching
{
    class Test
    {
        static void Main()
        {
            int valueOne = 10;
            int valueTwo = 20;

            Console.WriteLine("Testing valueOne against valueTwo...");
            if ( valueOne > valueTwo )
            {
                Console.WriteLine(
                    "ValueOne: {0} larger than ValueTwo: {1}", 
                    valueOne, valueTwo);
            }       // end if
            else 
            { 
                Console.WriteLine( 
                    "Nope, ValueOne: {0} is NOT larger than ValueTwo: {1}",  
                    valueOne, valueTwo); 
            }       // end else 

        }           // end Main
    }               // end class
}                   // end namespace
 Output:
Testing valueOne against valueTwo...
Nope, ValueOne: 10 is NOT larger than ValueTwo: 20

Because the test in the if statement fails (valueOne is not larger than valueTwo), the body of the if statement is skipped and the body of the else statement is executed. Had the test succeeded, the if statement body would execute and the else statement would be skipped.

6.2.4 Nested if Statements

It is possible, and not uncommon, to nest if statements to handle complex conditions. For example, suppose you need to write a program to evaluate the temperature and specifically to return the following types of information:

  • If the temperature is 32 degrees or lower, the program should warn you about ice on the road.

  • If the temperature is exactly 32 degrees, the program should tell you that there may be ice patches.

  • If the temperature is higher than 32 degrees, the program should assure you that there is no ice.

There are many good ways to write this program. Example 6-6 illustrates one approach, using nested if statements.

Example 6-6. Nested if statements
using System;
class Values
{
   static void Main()
   {
      int temp = 32;

      if (temp <= 32)
      {
         Console.WriteLine("Warning! Ice on road!");
         if (temp == 32)
         {
           Console.WriteLine(
            "Temp exactly freezing, beware of water.");
         }
         else
         {
            Console.WriteLine("Watch for black ice! Temp: {0}", temp);
         }
      }

   }
}

The logic of Example 6-6 is that it tests whether the temperature is less than or equal to 32. If so, it prints a warning:

if (temp <= 32)
{
   Console.WriteLine("Warning! Ice on road!");

The program then checks whether the temp is equal to 32 degrees. If so, it prints one message; if not, the temp must be less than 32 and the program prints the next message. Notice that this second if statement is nested within the first if, so the logic of the else statement is: "since it has been established that the temp is less than or equal to 32, and it isn't equal to 32, it must be less than 32."

The less-than-or-equal-to operator is <= and the equals operator is ==. Notice that the equals operator is two equal signs. C# considers this a single operator, as described in Chapter 7.

6.2.5 Switch Statements

Nested if statements are hard to read, hard to get right, and hard to debug. When you have a complex set of choices to make, the switch statement is a more powerful alternative. The logic of a switch statement is this: "pick a matching value and act accordingly."

switch  (expression )
{
   case  constant-expression : 
      statement 
      jump-statement 
    [default:  statement ]
}

The expression you are "switching on" is put in parentheses in the head of the switch statement. Each case statement compares a constant value with the expression. The constant expression can be a literal, symbolic, or enumerated constant.

The compiler starts with the first case statement and works its way down the list, looking for a value that matches the expression. If a case is matched, the statement (or block of statements) associated with that case is executed.

The case block must end with a jump statement. Typically, the jump statement is break, which abruptly ends the entire switch statement. When you execute a break in a switch statement, execution continues after the closing brace of the switch statement. (We'll consider the use of the optional default keyword later in this section.)

In the next, somewhat whimsical listing (Example 6-7), the user is asked to choose his political affiliation among Democrat, Republican, or Progressive. To keep the code simple, I'll hardwire the choice to be Republican.

Example 6-7. Using a switch statement
using System;

class Values
{
    static void Main()
    {
        const int Democrat = 0;
        const int Republican = 1;
        const int Progressive = 2;
        
        // hard wire to Republican
        int myChoice = Republican;

        // switch on the value of myChoice
        switch (myChoice)
        {
            case Democrat:
                Console.WriteLine("You voted Democratic.");
                break;
            case Republican:
                Console.WriteLine("You voted Republican.");
                break;
            case Progressive:
                Console.WriteLine("You voted Progressive.");
                break;
        }
        Console.WriteLine("Thank you for voting.");
    }
}
Output:
You voted Republican.
Thank you for voting.

Rather than using a complicated if statement, Example 6-7 uses a switch statement. The user's choice is evaluated in the head of the switch statement, and the block of statements that gets executed depends on whatever case matches (in this instance, Republican).

The statements between the case statement and the break are executed in series. You can have more than one statement here without braces; in effect the case statement and the closing break statement act as the braces.

It is possible that the user will not make a choice among Democrat, Republican, and Progressive. You may want to provide a default case that will be executed whenever no valid choice has been made. Do that with the default keyword, as shown in Example 6-8.

Example 6-8. A default statement
using System;

class Values
{
    static void Main()
    {
        const int Democrat = 0;
        const int Republican = 1;
        const int Progressive = 2;
        
        // hard wire to Republican
        int myChoice = 5;

        // switch on the value of myChoice
        switch (myChoice)
        {
            case Democrat:
                Console.WriteLine("You voted Democratic.\n");
                break;
            case Republican:
                Console.WriteLine("You voted Republican.\n");
                break;
            case Progressive:
                Console.WriteLine("You voted Progressive.\n");
                break;
            default:
                Console.WriteLine("You did not make a valid choice.");
                break;
        }
        Console.WriteLine("Thank you for voting.");
    }
}
Output
You did not make a valid choice.
Thank you for voting.

If the user does not choose one of the values that correspond to a case statement, the default statements will execute. In this case, a message is simply printed telling the user he did not make a valid choice.

6.2.6 Falling Through and Jumping to Cases

If two cases will execute the same code, you can create what's known as a "fall through" case, grouping the case statements together with the same code, as shown here:

case CompassionateRepublican:
case Republican:
    Console.WriteLine("You voted Republican.\n");
    Console.WriteLine("Don't you feel compassionate?");
    break;

In this example, if the user chooses either CompassionateRepublican or Republican, the same set of statements will be executed.

Note that you can only fall through if the first case executes no code. In this example, the first case, CompassionateRepublican, meets that criteria. Thus, you can fall through to the second case.

If, however, you want to execute a statement with one case and then fall through to the next, you must use the goto keyword to jump to the next case you want to execute.

The goto keyword is an unconditional branch. When the compiler sees this word, it immediately transfers the flow (jumps) to wherever the goto points to. Thus, even within this conditional branching statement, you've inserted an unconditional branch.

For example, if you create a NewLeft party, you might want the NewLeft voting choice to print a message and then fall through to Democrat (that is, continue on with the statements in the Democrat case). You might (incorrectly) try writing the following:

case NewLeft:
    Console.WriteLine("The NewLeft members are voting Democratic.");
case Democrat:
    Console.WriteLine("You voted Democratic.\n");
    break;

This code will not compile; it will fail with the error:

Control cannot fall through from one case label (case '4:') to another

This is a very misleading error message. Control can fall through from one case label to another, but only if there is no code in the first case label.

Notice that the error displays the name of the case with its numeric value (4) rather than its symbolic value (NewLeft). Remember that NewLeft is just the name of the constant:

const int Democrat = 0;
const int CompassionateRepublican = 1;
const int Republican = 2;
const int Progressive = 3

Because the NewLeft case has a statement, the WriteLine() method, you must use a goto statement to fall through:

case NewLeft:
    Console.WriteLine("The NewLeft members are voting Democratic.");
    goto case Democrat;
case Democrat:
    Console.WriteLine("You voted Democratic.\n");
    break;

This code will compile and execute as you expect.

The goto can jump over labels; you do not need to put NewLeft just above Democrat. In fact, you can put NewLeft last in the list (just before default), and it will continue to work properly.

6.2.7 Switch on string Statements

In the previous example, the switch value was an integral constant. C# also offers the ability to switch on a string. Thus, you can rewrite Example 6-8 to switch on the string "NewLeft," as in Example 6-9.

Example 6-9. Switching on a string
using System;

class Values
{
    static void Main()
    {
        String myChoice = "NewLeft";

        // switch on the string value of myChoice
        switch (myChoice)
        {
            case "NewLeft":
                Console.WriteLine(
                 "The NewLeft members are voting Democratic.");
                goto case "Democrat";  
            case "Democrat":
                Console.WriteLine("You voted Democratic.\n");
                break;
            case "CompassionateRepublican": // fall through
            case "Republican":
                Console.WriteLine("You voted Republican.\n");
                Console.WriteLine("Don't you feel compassionate?");
                break;
            case "Progressive":
                Console.WriteLine("You voted Progressive.\n");
                break;
            default:
                Console.WriteLine("You did not make a valid choice.");
                break;
        }
        Console.WriteLine("Thank you for voting.");
    }
}
    Team LiB   Previous Section   Next Section