Conditional Branching Statements

Although 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.” This is where the comparison operators you learned about in Chapter 4 become really useful.

C# provides a number of constructs that allow you to write conditional branches into your programs, including the if, else, and switch statements.

if Statements

The simplest branching statement is if. An if statement says, “If a particular condition is true, then execute the following statement; otherwise, skip it.” The condition is a Boolean expression. As you learned in Chapters Chapter 3 and Chapter 4, a Boolean expression evaluates to either true or false, which makes it a perfect fit for the if statement.

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. Statement1 doesn’t have to be just one statement—it can actually be a block of statements within braces. As long as you include the braces, the compiler treats your code as just one statement. Example 5-2 shows how this works.

Example 5-2. The if statement evaluates an expression, and executes a statement if the expression is true, or skips it if the expression is false

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Example_5_2_ _ _ _The_if_Statement
{
    class Program
    {
        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);
            }
        }
    }
}

Tip

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

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). Therefore, the body of the if statement (the statements within the braces) doesn’t execute, and the WriteLine never executes.

You then test whether valueThree is greater than valueTwo:

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

Because 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

Single-Statement if Blocks

Notice that the if statement blocks shown in Example 5-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 5-2 as shown in Example 5-3.

Example 5-3. When your if statement block contains only a single statement, you can leave out the braces

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Example_5_3_ _ _ _if_Block_without_Braces
{
    class Program
    {
        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);
        }
    }
}

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.

Tip

When programmers talk about maintaining code, they mean either adding to the code as requirements change or fixing the code as bugs are discovered. You may find yourself maintaining code that you wrote months or years ago, or maintaining code somebody else wrote. In those cases, clear, readable code is a lifesaver.

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 5-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 5-4. When you add a second statement to an if block, be sure to enclose it in the braces, or you may get unexpected results

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Example_5_4_ _ _ _Adding_to_an_if_Block
{
    class Program
    {
        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!");
        } 
    }
}

Now, before reading any further, review the code and decide 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. Indentation is whitespace, and as we mentioned in Chapter 3, whitespace is ignored by the compiler. From the perspective of the programmer, the second statement (“Good thing . . . “) looks to be 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.

Short-Circuit Evaluation

Consider the following code snippet:

int x = 8;
int y = 15;
if ((x == 8) || (y == 12))

The if statement here is a bit complicated. The entire if statement is in parentheses, as are all if statements in C#. Thus, everything within the outer set of parentheses must evaluate true for the if statement to be true.

Within the outer parentheses are two expressions, (x == 8) and (y == 12), which are separated by an or operator (||). Because x is 8, the first term (x == 8) evaluates true. There is no need to evaluate the second term (y == 12). It doesn’t matter whether y is 12; the entire expression will be true, because the first part is true. (Remember, for an or statement to evaluate true, just one of the expressions has to be true.) Similarly, consider this snippet:

int x = 8;
int y = 12;
if ((x == 5) && (y == 12))

Again, there is no need to evaluate the second term. Because the first term is false, the and must fail. (Remember, for an and statement to evaluate true, both tested expressions must evaluate true.)

In cases such as these, the C# compiler will short-circuit the evaluation; the second test will never be performed. This allows you to create if statements in which you first check a value before you take action on it, avoiding the possibility of an exception. Here’s a short example:

public bool QuotientOverTwenty(float dividend, float divisor)
{
   if ( ( divisor != 0 ) && ( dividend / divisor > 20 ) )
   {
      return true;
   }
   return false;
}

In this code, you want to determine whether the quotient is greater than 20, but you must first make sure you are not dividing by zero (division by zero causes the system to throw an exception). With short-circuiting, the second part of the if statement (the division) will never occur if the first part is false (that is, if the divisor is zero).

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 follows the else statement. For example, you can modify Example 5-2 to print an appropriate message whether or not valueOne is greater than valueTwo, as shown in Example 5-5.

Example 5-5. Adding an else statement to your if statement lets you take an action if the condition in the if statement is false—it’s the “or” to the if’s “either”

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Example_5_5_ _ _ _The_else_Statement
{
    class Program
    {
        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);
            } 
            else
            {
                Console.WriteLine("Nope, ValueOne: {0} is NOT larger than ValueTwo: 
                                  {1}", valueOne, valueTwo);
            } 
        } 
    }
}

The output looks like this:

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.

Nested if Statements

You’ve seen how to make your if statement take action for two possible options, but what if there are more than two choices? In that case, you can nest if statements—that is, contain one if inside another—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 water on the road.

  • 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 5-6 illustrates one approach using nested if statements.

Example 5-6. You can nest if statements safely, one inside the other

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Example_5_6_  _  _  _Nested_if_Statements
{
    class Program
    {
        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);
                }
            }
            else
            {
                Console.WriteLine("No ice; drive with confidence.");
            }
        }
    }
}

The logic of Example 5-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 temperature is equal to 32 degrees. If so, it prints one message; if not, the temperature 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: “because it has been established that the temperature is less than or equal to 32, and it isn’t equal to 32, it must be less than 32.”

Another way you can chain together more than one possibility with if statements is to use the else if idiom. The program tests the condition in the first if statement. If that first statement is false, control passes to the else statement, which is immediately followed by another if that tests a different condition. For example, you could rewrite Example 5-6 to test whether the temperature is greater than, less than, or exactly equal to freezing with three tests, as shown in Example 5-7.

Example 5-7. The else if construct is another way of chaining together if statements without nesting

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Example_5_7_ _ _ _else_if
{
    class Program
    {
        static void Main( )
        {
            int temp = 32;

            if (temp < 32)
            {
                Console.WriteLine("Warning! Ice on road!");
            }
            else if (temp == 32)
            {
                Console.WriteLine("Temp exactly freezing, beware of water.");
            }
            else
            {
                Console.WriteLine("No ice; drive with confidence.");
            }
        }
    }
}

In this case, the condition in the first if statement tests whether temp is less than 32, not less than or equal to 32. Because temp is hardwired to exactly 32, the first expression is false, and control passes to the else if statement. The second statement is true, so the third case, the else statement, never executes. Please note, however, that this code is identical (as far as the compiler is concerned) to the following:

static void Main( )
{
   int temp = 32;
   if ( temp < 32 )
   {
      Console.WriteLine( "Warning! Ice on road!" );
   }
   else
   {
       if ( temp == 32 )
       {
         Console.WriteLine("Temp exactly freezing, beware of water.");
       }
       else
      {
         Console.WriteLine("No ice; drive with confidence.");
      }
   }
}

In any case, if you do use the else if idiom, be sure to use an else (not an else if) as your final test, making it the default case that will execute when nothing else does.

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 testing (or “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 5-8), the user is asked to choose her political affiliation among Democrat, Republican, or Progressive. To keep the code simple, we’ll hard-wire the choice to be Democrat.

Example 5-8. Use a switch statement to compare a value to a set of constants, and take action accordingly; a switch statement is easier to use and more readable than nested if statements

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Example_5_8_ _ _ _The_switch_Statement
{
    class Program
    {
        enum Party
        {
            Democrat,
            Republican,
            Progressive
        }
        static void Main( )
        {
            // hardwire to Democratic
            Party myChoice = Party.Democrat;

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

The output looks like this:

You voted Democratic.
Thank you for voting.

Rather than using a complicated if statement, Example 5-8 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, Democrat).

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.

We hardwired the choice here, but if you’re accepting user input instead, 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. You can do that with the default keyword, as shown in Example 5-9. This example already has some built-in safety, because you can’t hard-wire a choice that’s not a member of the enum, and the switch statement has a block for each possible member of the enum. We’ve commented out the Democrat choice, making it invalid, so that you can see the default statement at work.

Example 5-9. The default statement gives you a backup that will always be executed, if the user doesn’t make a valid choice

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Example_5_9_ _ _ _The_default_statement
{
    class Program
    {
        enum Party
        {
            Democrat,
            Republican,
            Progressive
        }
        static void Main( )
        {
            // hardwire to Democratic
            Party myChoice = Party.Democrat;

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

The output looks like this:

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 statement will execute. In this case, a message is simply printed telling the user she did not make a valid choice; in production code, you would put all this in a while loop, re-prompting the user until a valid choice is made (or the user elects to quit).

Fall-Through and Jump-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.
");
     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 fall through only if the first case executes no code. In this example, the first case, CompassionateRepublican, meets that criterion. 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.

Tip

The goto keyword is an unconditional branch. When the compiler sees this word, it immediately transfers the flow (jumps) to wherever the goto points. 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, to 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.
");
     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 potentially 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.

Tip

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. Behind the scenes of your enum, the values look like this:

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

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.
");
     break;

This code will compile and execute as you expect.

Tip

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.

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 5-9 to switch on the string "NewLeft", as in Example 5-10.

Example 5-10. You can switch on a string, as well as on an integral constant

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Example_5_10_ _ _ _Switching_on_a_String
{
    class Program
    {
        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.
");
                    break;
                case "CompassionateRepublican": // fall through
                case "Republican":
                    Console.WriteLine("You voted Republican.
");
                    Console.WriteLine("Don't you feel compassionate?");
                    break;
                case "Progressive":
                    Console.WriteLine("You voted Progressive.
");
                    break;
                default:
                    Console.WriteLine("You did not make a valid choice.");
                    break;
            }
            Console.WriteLine("Thank you for voting.");
        }
    }
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset