4.2. Conditional (if) Statements#

4.2.1. Simple if Statements#

The if statement specifies a block of C# code to be executed if a condition is True.

if (condition)
{
    // block of code to be executed if the condition is True
}

Note

Note that C# is case sensitive, so If is not the same as if. “If” or “IF” will generate an error.

In if statements, the comparison operators (>, <, >=, <=, ==, and !=) are used to evaluate the comparison expressions to derive a value of either true or false from the Boolean expression.

The first step to learn about the if statements is to perform some tests on the operators in csharprepl such as:

if (20 > 10)
{
Console.WriteLine("20 is greater than 10");
}

with the output:

20 is greater than 10

When coding, we often play with variables rather than simple values. Observe the following code and test it in csharprepl to practice if statements with variables:

int num1 = 20;
int num2 = 18;
if (num1 > num2)
{
Console.WriteLine("num1 is greater than num2");
}

Consider simple arithmetic comparisons that directly translate from math into C#. In csharprepl, enter:

int num = 11;

Now think of which of these expressions below are true and which false, and then enter each one into your csharp session to test:

2 < 5
3 > 7
num > 10
2*x < num

You see that the expressions evaluate to either true or false. These are the only possible Boolean values.

Run the example program below. Try it at least twice, with inputs: 30 and then 55. As you can see, you get different results, depending on the input. The main code is:

// namespace IntroCSCS

class Chapter04
{
   static void Main(string[] args)
   {
      Weight();
   }

   public static void Weight()
   {
      Console.Write("How many pounds does your suitcase weigh? ");

      double weight = double.Parse(Console.ReadLine());
      
      if (weight > 50)
      {
         Console.WriteLine("There is a $25 charge for luggage that heavy.");
      }
      
      Console.WriteLine("Thank you for your business.");      
   }
}

In this code, following line numbers as:

  • #5: The Main() method in the Chapter04 class called the Weight() method (line #10).

  • #16: the if statement in the Weight() method test the condition inside the parentheses.

    • If the condition is true that the weight is greater than 50, then the code block #17-19 would run, printing that there will be a $25 charge.

  • #21: No matter whether the if statement (#14-17) runs or not, print the “thank you” message.

You can see from this code that:

  1. the general C# syntax for a simple if statement is:

if (condition)
{
   // statement(s)
}
  1. If the condition is true, then execute the statement(s) in braces. If the condition is not true, then skip the statements in braces.

  2. The condition is an expression that evaluates to either true or false, of type boolean.

  3. An if statement only affects the normal sequential order inside the if statement itself (e.g., skipping the extra charge block when the condition is not true and still print the “thank you” line).

Another code fragment of banking account transaction as an example:

if (balance < 0) { transfer = - balance; // transfer enough from the backup account: backupAccount = backupAccount - transfer; balance = balance + transfer; }

The assumption in the example above is that if an account goes negative, it is brought back to 0 by transferring money from a backup account. Note that the choice is between

  • doing something (if the condition is true) or

  • nothing (if the condition is false).

4.2.2. if-else Statements: Two-Way Selection#

Since we can usually start analyzing a problem by coming up with two possibilities, it makes sense to add the alternative action to the code, which makes the if-else statements.

The general C# if-else syntax is:

if (condition)
{
    // statement(s) for if-true;
}
else 
{
    // statement(s) for if-false;
}

Let us start by running the following example code (Clothes() method in Chapter04.cs). Try it at least twice, with inputs 50 and then 80. As you can see, you get different results, depending on the input.

 1// namespace IntroCSCS
 2// {
 3
 4class Chapter04
 5{
 6public static void Main(string[] args)
 7{
 8// Rolla();
 9// Weight();
10   Clothes();
11}
12
13   public static void Clothes()
14   {
15      Console.Write("What is the temperature? ");
16      double temperature = double.Parse(Console.ReadLine());
17      if (temperature > 70)
18         {
19            Console.WriteLine("Wear shorts.");
20         }
21      else
22         {
23            Console.WriteLine("Wear long pants.");
24         }
25      Console.WriteLine("Get some exercise outside.");
26   }
27
28}
29// }

You may see a warning in VS Code and when running the code as

warning CS8604:
Possible null reference argument for parameter 's' in 'double double.Parse(string s)'.

You can safely disregard the warning message. Basically, C# compiler produces warning at that line because argument of Parse is marked as “non-nullable” and the compiler determined that the parameter input you are passing to that call can be null at the point of call. For more information about this warning, see C# language reference.

After running the code, you see that the if-else statement allows you to choose which of the two code paths to follow based on a Boolean expression. In an if-else statement, an if statement is followed by an else statement that is only executed when the original if condition is false. Note that in an if-else statement, exactly one of two possible code blocks in braces is executed.

A final print line is also shown that is not indented, about getting exercise. The if and else clauses each only embed a single (possibly compound) statement as option, so the last statement is not part of the if-else statement. It is beyond the if-else statement. It is just a part of the normal sequential flow of statements and therefore will be executed as part of the flow.

Scope in Compound Statements

Just like the local scope in method bodies, which happen to be enclosed in braces, making the function body a compound statement. In fact variables declared inside any compound statement have their scope restricted to inside that compound statement. As a result the following code makes no sense:

static int BadBlockScope(int x)
{
    if (x < 100) {
        int val = x + 2;
    }
    else {
        int val = x - 2;
    }
    return val;
}

The if-else statement is legal, but useless, because whichever compound statement gets executed, val ceases being defined after the closing brace of its compound statement, so the val in the return statement has not been declared or given a value. The code would generate a compiler error.

If we want val to be used inside the braces and to make sense past the end of the compound statement, it cannot be declared inside the braces. Instead it must be declared before the compound statements that are parts of the if-else statement. A local variable in a function declared before a nested compound statement is still visible (in scope) inside that compound statement.

4.2.3. else-if Statements: Multi-Selection#

if-else statements allow us to construct two alternative paths. A single condition determines which path will be followed. We can build more complex conditionals using an else if clause, with which you can pick between 3 or more possibilities. These allow us to add additional conditions and code blocks, which facilitate more complex branching.

4.2.4. else-if Statements#

Comparing with the if-else statement, the else if statements specify a new condition to be tested if the first condition is False.

The syntax for the else-if statement is:

if (condition1)
{
    // block of code to be executed if condition1 is True
}
else if (condition2)
{
    // block of code to be executed if the condition1 is False and condition2 is True
}
else
{
    // block of code to be executed if the condition1 is False and condition2 is False
}

Note that the logic of the flow terminate at else: The else block is the default block when all the conditions are False.

An example of else-if statement is:

int x = 10;
int y = 20;

if (x > y)
{
Console.WriteLine("x is greater than y");
}
else if (x < y)
{
Console.WriteLine("x is less than y");
}
else
{
Console.WriteLine("x and y are equal");
}

In the example above, the logic is that the three conditions can exhaust all possible alternatives. If the first condition is False, the next condition, in the else-if statement, will be tested. If the 2nd condition is also False, we then move on to the else statement, the default case, since condition1 and condition2 are both False.

The code below is a variation of the Weight() method. Consider this fragment without a final else:

if (weight > 120) {
    Console.WriteLine("Sorry, we can not take a suitcase that heavy.");
}
else if (weight > 50) {
    Console.WriteLine("There is a $25 charge for luggage that heavy.");
}

As with a simple if statement, the else clause is optional in else-if statements. This code above only prints one of two lines if there is a problem with the weight of the suitcase (> 50 or > 120). Nothing is printed if neither of the conditions is met, meaning the weight is not greater than 50.

4.2.5. else-if Statements for Cases#

Consider the following code, LetterGrade() method, for converting a numerical grade to a letter grade, ‘A’, ‘B’, ‘C’, ‘D’ or ‘F’, where the cutoffs for ‘A’, ‘B’, ‘C’, and ‘D’ are 90, 80, 70, and 60 respectively. We repetitively nests the if statements in the else clauses. The code structure is legal but semantically unsound if we consider the grade letters to be a flat structure:

static char LetterGrade(double score)
{
    char letter;
    if (score >= 90) {
        letter = 'A';
    }
    else {   // grade must be B, C, D or F
        if (score >= 80) {
            letter = 'B';
        }
        else { // grade must be C, D or F
            if (score >= 70) {
            letter = 'C';
            }
            else {   // grade must D or F
            if (score >= 60) {
                letter = 'D';
            }
            else {
                letter = 'F';
            }
            }   //end else D or F
        }      // end of else C, D, or F
    }         // end of else B, C, D or F
    return letter;
}

As seen in the LetterGrade() method above, the repeatedly increasing indentation with an if statement in the else clause can be annoying and distracting. Here is a preferred alternative in this situation, that avoids all this further indentation: Combine each else and following if onto the same line, and note that the if part after each else is just a single (possibly very complicated) statement. This allows the elimination of some of the braces and make the code more readable and logically clear:

if (

condition1

) {

statement-block-run-if-condition1-is-true;

}

else if (

condition2

) {

statement-block-run-if-condition2-is-the-first-true;

}

else if (

condition3

) {

statement-block-run-if-condition3-is-the-first-true;

}

// …

else {    //

no condition!

statement-block-run-if-no condition-is-true;

}

Note that exactly one of the statement blocks gets executed: - If some condition is true, the first block following a true condition is executed. - If no condition is true, the else block is executed.

We can modify the LetterGrade() method into LetterGrade2() method using else if, which is more readable and semantically sound:

static char LetterGrade2(double score)
{
    char letter;
    if (score >= 90) {
        letter = 'A';
    }
    else if (score >= 80) {
        letter = 'B';
        }
    else if (score >= 70) {
        letter = 'C';
    }
    else if (score >= 60) {
        letter = 'D';
    }
    else {
        letter = 'F';
    }
    return letter;
}

4.2.6. Nested Conditionals#

The problem-solving scenario that you want to model may require complex branching behavior by combining conditionals and, in particular, by nesting conditionals. Namely, we can create more complex branching behavior by nesting conditional blocks. When more than one condition needs to be true and one of the condition is the sub-condition of parent condition, nested if can be used. In other words, when we want to further test certain condition when a condition tested true.

4.2.7. Nested if Statements#

The syntax for a nested if statement is as follows:

if( boolean_expression 1)
{
   /* Executes when the boolean expression 1 is true */
   if(boolean_expression 2)
   {
      /* Executes when the boolean expression 2 is true */
   }
}

As an example, consider the following code where two separate but related ideas are tested using two independent if statements:

int num = 7;

if (num > 0)
{
   Console.WriteLine("POSITIVE");
}

if (num % 2 == 0)
{
   Console.WriteLine("EVEN");
}

We find that the output is POSITIVE, even though 7 is odd and so nothing should be printed in the 2nd if statement. This code doesn’t work as desired if we only want to test for evenness only when we already know the number is positive. We can enable this behavior by putting the second conditional inside the first as:

int num = 7;

if (num > 0)
{
   Console.WriteLine("POSITIVE");

   if (num % 2 == 0)
   {
      Console.WriteLine("EVEN");
   }
}

Notice that when we put one conditional inside another, the body of the nested conditional is indented by two tabs rather than one. This convention provides an easy, visual way to determine which code is part of which conditional.

Note that nested if statements can also contain an else statement. When working with nested statements, the else clause belongs to the last unpaired if. You can only use an else when you have an if.

int num = 7;

if(num < 9)
{
if (num % 2 == 0)
{
Console.WriteLine("EVEN");
}

else
{
Console.WriteLine("ODD");
}
}

4.2.8. Nested if-else Statements#

Often you want to distinguish between more than two distinct cases,
but conditions only have two possible results, `true` or `false`,
so the only direct choice is between two options. If there are
more than two choices, a single test may only reduce the
possibilities, but further tests can reduce the possibilities
further and further until the possibilities are exhausted. Since almost
any kind of statement can be placed in the sub-statements in
an {{ if_else }} statement, one choice is a further `if` or {{ if_else }} statement.

For instance, consider the LetterGrade() method that you have seen earlier.
One way to write the method would be to test for one grade at a time, and
resolve all the remaining possibilities inside the next `else` clause.

If we do this consistently with our indentation conventions so far:

static char LetterGrade(double score) { char letter; if (score >= 90) { letter = ‘A’; } else { // grade must be B, C, D or F if (score >= 80) { letter = ‘B’; } else { // grade must be C, D or F if (score >= 70) { letter = ‘C’; } else { // grade must D or F if (score >= 60) { letter = ‘D’; } else { letter = ‘F’; } } //end else D or F } // end of else C, D, or F } // end of else B, C, D or F return letter; } ```

When working with else statements in nested conditionals, remember that the else is paired with the last if that doesn’t have already have an else. In the example above, the else statement in line 10 belongs to the if in line 5. else and else if rules apply the same way within nested conditionals as in un-nested ones.

In if-else statements, the sub-statements (the if-true and if-false clauses) are quite arbitrary statements. There can be more if or if-else sub-statements.

In method LetterGrade() above, we place an if-else statement as the else clause, and repeating this pattern, to repeatedly test for one more case, stopping when the first true condition if reached.

Footnotes