ms_learn_csharp/008_if_else/008_csharp.md

804 lines
27 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Introduction
The C# programming language allows you to build applications that employ
decision-making logic.
Suppose you want to display different information to the end user depending on
some business rules. For example, what if you want to display a special
message on a customer's bill based on their geographic region? What if you
want to give a customer a discount based on the size of their order? Or what
if you want to display an employee's title based on their level in the company.
In each case, you would need to add decision logic.
By the end of this module, you'll be able to write code that can change the
flow of your code's execution based on some criteria.
> Important
> This module includes coding activities that require Visual Studio Code. You'll
need access to a development environment that has Visual Studio Code installed
and configured for C# application development.
### Learning objectives
In this module, you will:
- Write code that evaluates conditions by using the statements `if`, `else`,
and `else if`.
- Build Boolean expressions to evaluate a condition.
- Combine Boolean expressions using logical operators.
- Nest code blocks within other code blocks.
#### Prerequisites
- Experience using Visual Studio Code to create and run C# console applications.
- Experience printing messages to the console using `Console.WriteLine()`.
- Experience with string interpolation to combine variables into literal
strings.
- Experience working with the System.Random class to generate random numbers.
---
## Exercise
### Create decision logic with if statements
Most applications include a large number of execution paths. For example, an
application could implement different execution paths based on which menu
option a user selects. Developers refer to the code that implements different
execution paths as code branches.
The most widely used code branching statement is the `if` statement. The `if`
statement relies on a Boolean expression that is enclosed in a set of
parentheses. If the expression is true, the code after the `if` statement is
executed. If not, the .NET runtime ignores the code and doesn't execute it.
In this exercise, you'll practice writing `if` statements by creating a game.
First you'll define the rules of the game, then you'll implement them in code.
You'll use the `Random.Next()` method to simulate rolling three six-sided dice.
You'll evaluate the rolled values to calculate the score. If the score is
greater than an arbitrary total, then you'll display a winning message to the
user. If the score is below the cutoff, you'll display a losing message to the
user.
- If any two dice you roll result in the same value, you get two bonus points
for rolling doubles.
- If all three dice you roll result in the same value, you get six bonus
points for rolling triples.
- If the sum of the three dice rolls, plus any point bonuses, is 15 or greate
r, you win the game. Otherwise, you lose.
You'll refine the rules as you learn more about the if statement.
> Important
> This exercise makes extensive use of the `System.Random` class. You can refer
to the Microsoft Learn module titled "Call methods from the .NET Class Library
using C#" if you need a refresher how `Random.Next()` works.
#### Prepare your coding environment
This module includes activities that guide you through the process of building
and running sample code. You're encouraged to complete these activities using
Visual Studio Code as your development environment. Using Visual Studio Code
for these activities will help you to become more comfortable writing and
running code in a developer environment that's used by professionals worldwide.
Open Visual Studio Code.
### Write code that generates three random numbers and displays them in output
Ensure that you have an empty Program.cs file open in Visual Studio Code.
To create the initial code for this exercise, enter the following:
```cs
Random dice = new Random();
int roll1 = dice.Next(1, 7);
int roll2 = dice.Next(1, 7);
int roll3 = dice.Next(1, 7);
int total = roll1 + roll2 + roll3;
Console.WriteLine($"Dice roll: {roll1} + {roll2} + {roll3} = {total}");
```
Take a minute to review the code that you entered.
To begin, you create a new instance of the `System.Random` class and store a
reference to the object in a variable named `dice`. Then, you call the
`Random.Next()` method on the `dice` object three times, providing both the
lower and upper bounds to restrict the possible values between `1` and `6` (the
upper bound is exclusive). You save the three random numbers in the variables
`roll1`, `roll2`, and `roll3`, respectively.
Next, you sum the three dice rolls and save the value into an integer variable
named `total`.
Finally, you use the `WriteLine()` method to display the three values using
string interpolation.
When you run the code, you should see the following message (the numbers will
be different).
Output
```txt
Dice roll: 4 + 5 + 2 = 11
```
This first task was a setup task. Now, you can add the decision logic into
your code to make the game more interesting.
### Add an if statement to display different messages based on the value of the total variable
In the Visual Studio Code Editor, locate the cursor at the bottom of your code
file, and then create a blank code line.
To create your first game feature, enter the following if statements.
```cs
if (total > 14){
Console.WriteLine("You win!");
}
if (total < 15){
Console.WriteLine("Sorry, you lose.");
}
```
These two if statements are used to handle the winning and losing scenarios.
Take a minute to examine the first if statement.
Notice that the if statement is made up of three parts:
- The `if` keyword
- A Boolean expression between parenthesis `()`
- A code block defined by curly braces `{ }`
At run time, the Boolean expression `total > 14` is evaluated. If this is a
true statement (if the value of total is greater than `14`) then the flow of
execution will continue into the code defined in the code block. In other word
s, it will execute the code in the curly braces.
However, if the Boolean expression is false (the value of `total` not greater
than `14`) then the flow of execution will skip past the code block. In other
words, it will not execute the code in the curly braces.
Finally, the second `if` statement controls the message if the user loses. In
the next unit, you'll use a variation on the `if` statement to shorten these
two statements into a single statement that more clearly expresses the intent.
### What is a Boolean expression?
A Boolean expression is any code that returns a Boolean value, either `true` or
`false`. The simplest Boolean expressions are simply the values `true` and
`false`. Alternatively, a Boolean expression could be the result of a method that
returns the value `true` or `false`. For example, here's a simple code example
using the `string.Contains()` method to evaluate whether one string contains
another string.
```cs
string message = "The quick brown fox jumps over the lazy dog.";
bool result = message.Contains("dog");
Console.WriteLine(result);
if (message.Contains("fox")){
Console.WriteLine("What does the fox say?");
}
```
Because the `message.Contains("fox")` returns a `true` or `false` value, it
qualifies as a Boolean expression and can be used in an `if` statement.
Other simple Boolean expressions can be created by using operators to compare two values. Operators include:
- `==`, the "equals" operator, to test for equality
- `>`, the "greater than" operator, to test that the value on the left is greater than the value on the right
- `<`, the "less than" operator, to test that the value on the left is less than the value on the right
- `>=`, the "greater than or equal to" operator
- `<=`, the "less than or equal to" operator
- and so on
> Note
> The C# training series on Microsoft Learn devotes an entire module to
Boolean expressions. There are many operators you can use to construct a
Boolean expression, and you'll only cover a few of the basics here in this
module. For more on Boolean expressions, see the Microsoft Learn module titled
"Evaluate Boolean expressions to make decisions in C#".
In this example, you evaluated the Boolean expression `total > 14`. However,
you could have chosen the Boolean expression `total >= 15` because in this cas
e, they're the same. Given that the rules to the game specify "If the sum of
the three dice, plus any bonuses, is 15 or greater, you win the game", you
should probably implement the `>= 15` expression. You'll make that change in
the next step of the exercise.
### What is a code block?
A code block is a collection of one or more lines of code that are defined by
an opening and closing curly brace symbol `{ }`. It represents a complete unit
of code that has a single purpose in your software system. In this case, at
runtime, all lines of code in the code block are executed if the Boolean
expression is true. Conversely, if the Boolean expression is false, all lines
of code in the code block are ignored.
You should also know that code blocks can contain other code blocks. In fact,
it's common for one code block to be "nested" inside another code block in
your applications. You'll begin nesting your own code blocks later in this
module when you create one `if` statement inside the code block of another.
> Note
> The C# training series on Microsoft Learn devotes an entire module to
understanding code blocks. Code blocks are central to understanding code
organization and structure, and they define the boundaries of variable scope.
See the module [Control variable scope and logic using code blocks in C#](TBD).
### Add another if statement to implement the doubles bonus
Next, you can implement the rule: "If any two dice you roll result in the same
value, you get two bonus points for rolling doubles". Modify the code from the
previous step to match the following code listing:
In the Visual Studio Code Editor, locate the cursor on the blank code line
above the first `if` statement.
To create your "doubles" game feature, enter the following `if` statement.
```cs
if ((roll1 == roll2) || (roll2 == roll3) || (roll1 == roll3)){
Console.WriteLine("You rolled doubles! +2 bonus to total!");
total += 2;
}
```
Here you combine three Boolean expressions to create one composite Boolean
expression in a single line of code. This is sometimes called a compound
condition. You have one outer set of parentheses that combines three inner
sets of parentheses separated by two pipe characters.
The double pipe characters `||` are the **logical OR operator**, which
basically says "either the expression to my left OR the expression to my right
must be true in order for the entire Boolean expression to be true". If both
Boolean expressions are false, then the entire Boolean expression is false.
You use two logical OR operators so that you can extend the evaluation to a
third Boolean expression.
First, you evaluate `(roll1 == roll2)`. If that's true, then the entire
expression is true. If it's false, you evaluate `(roll2 == roll3)`. If that's
true, then the entire expression is true. If it's false, you evaluate
`(roll1 == roll3)`. If that's true, then the entire expression is true. If
that is false, then the entire expression is false.
If the composite Boolean expression is true, then you execute the following
code block. This time, there are two lines of code. The first line of code
prints a message to the user. The second line of code increments the value of
`total` by `2`.
To improve the readability of your code, update the second `if` statement as
follows:
```cs
if (total >= 15)
```
Notice that you're now using the `>=` operator in the expression that's used
to evaluate a winning roll. The `>=` operator means "greater or equal to". As a
result, you can compare `total` to a value of `15` rather than `14`. With
these changes, the expression that you use to evaluate a winning roll now
resembles the expression that you evaluate for a losing roll. This should help
to make your code easier to understand (more readable). Since you are dealing
with integer values, your new expression `(total >= 15)` will function
identically to what you wrote previously `(total > 14)`.
Take a minute to review your code.
Your code should match the following:
```cs
Random dice = new Random();
int roll1 = dice.Next(1, 7);
int roll2 = dice.Next(1, 7);
int roll3 = dice.Next(1, 7);
int total = roll1 + roll2 + roll3;
Console.WriteLine($"Dice roll: {roll1} + {roll2} + {roll3} = {total}");
if ((roll1 == roll2) || (roll2 == roll3) || (roll1 == roll3)){
Console.WriteLine("You rolled doubles! +2 bonus to total!");
total += 2;
}
if (total >= 15){
Console.WriteLine("You win!");
}
if (total < 15){
Console.WriteLine("Sorry, you lose.");
}
```
Notice the improved alignment between the expressions used to evaluate winning
and losing rolls.
### Add another if statement to implement the triples bonus
Next, you can implement the rule: "If all three dice you roll result in the
same value, you get six bonus points for rolling triples." Modify the code
from the previous steps to match the following code listing:
In the Visual Studio Code Editor, create a blank code line below the code
block of your "doubles" `if` statement.
To create your "triples" game feature, enter the following `if` statement.
```cs
if ((roll1 == roll2) && (roll2 == roll3)) {
Console.WriteLine("You rolled triples! +6 bonus to total!");
total += 6;
}
```
Here you combine two Boolean expressions to create one composite Boolean
expression in a single line of code. You have one outer set of parentheses
that combines two inner sets of parentheses separated by two ampersand
characters.
The double ampersand characters `&&` are the **logical AND** operator, which
basically says "only if both expressions are true, then the entire expression
is true". In this case, if `roll1` is equal to `roll2`, and `roll2` is equal to
`roll3`, then by deduction, roll1 must be equal to roll3, and the user rolled
triples.
On the Visual Studio Code File menu, click Save.
Take a minute to review your code.
Ensure that your code matches the following:
```cs
Random dice = new Random();
int roll1 = dice.Next(1, 7);
int roll2 = dice.Next(1, 7);
int roll3 = dice.Next(1, 7);
int total = roll1 + roll2 + roll3;
Console.WriteLine($"Dice roll: {roll1} + {roll2} + {roll3} = {total}");
if ((roll1 == roll2) || (roll2 == roll3) || (roll1 == roll3)){
Console.WriteLine("You rolled doubles! +2 bonus to total!");
total += 2;
}
if ((roll1 == roll2) && (roll2 == roll3)) {
Console.WriteLine("You rolled triples! +6 bonus to total!");
total += 6;
}
if (total >= 15){
Console.WriteLine("You win!");
}
if (total < 15){
Console.WriteLine("Sorry, you lose.");
}
```
You should see output that resembles one of the following results:
```txt
Dice roll: 3 + 6 + 1 = 10
Sorry, you lose.
```
Or, like this:
```txt
Dice roll: 1 + 4 + 4 = 9
You rolled doubles! +2 bonus to total!
Sorry, you lose.
```
Or, like this:
```txt
Dice roll: 5 + 6 + 4 = 15
You win!
```
Or, if you're lucky, you'll see this:
```txt
Dice roll: 6 + 6 + 6 = 18
You rolled doubles! +2 bonus to total!
You rolled triples! +6 bonus to total!
You win!
```
But wait, should you really reward the player with both the triple bonus and
the double bonus? After all, a roll of triples implies that they also rolled
doubles. Ideally, the bonuses shouldn't stack. There should be two separate
bonus conditions. This is a bug in logic that will need to be corrected.
### Problems in your logic and opportunities to improve the code
Although this is a good start, and you've learned a lot about the if statement,
Boolean expressions, code blocks, logical OR and AND operators, and so on,
there's much that can be improved. You'll do that in the next unit.
### Recap
- Use an `if` statement to branch your code logic. The `if` decision statement
will execute code in its code block if its Boolean expression equates to true.
Otherwise, the runtime will skip over the code block and continue to the next
line of code after the code block.
- A Boolean expression is any expression that returns a Boolean value.
- Boolean operators will compare the two values on its left and right for
equality, comparison, and more.
- A code block is defined by curly braces `{ }`. It collects lines of code
that should be treated as a single unit.
- The logical AND operator `&&` aggregates two expressions so that both
subexpressions must be true in order for the entire expression to be true.
- The logical OR operator `||` aggregates two expressions so that if either
subexpression is true, the entire expression is true.
---
## Exercise
### Create nested decision logic with if, else if, and else
In the previous unit, you used multiple `if` statements to implement the rules
of a game. However, at the end of the unit, you noticed that more expressive
`if` statements are needed to fix a subtle bug in your code.
In this exercise, you'll use `if`, `else`, and `else if` statements to improve
the branching options in your code and fix a logic bug.
### Use if and else statements instead of two separate if statements
Instead of performing two checks to display the "You win!" or "Sorry, you lose"
message, you'll use the `else` keyword.
Ensure that your Program.cs code matches the following:
```cs
Random dice = new Random();
int roll1 = dice.Next(1, 7);
int roll2 = dice.Next(1, 7);
int roll3 = dice.Next(1, 7);
int total = roll1 + roll2 + roll3;
Console.WriteLine($"Dice roll: {roll1} + {roll2} + {roll3} = {total}");
if ((roll1 == roll2) || (roll2 == roll3) || (roll1 == roll3)){
Console.WriteLine("You rolled doubles! +2 bonus to total!");
total += 2;
}
if ((roll1 == roll2) && (roll2 == roll3)) {
Console.WriteLine("You rolled triples! +6 bonus to total!");
total += 6;
}
if (total >= 15){
Console.WriteLine("You win!");
}
if (total < 15){
Console.WriteLine("Sorry, you lose.");
}
```
This is the code that you completed in the previous unit.
Take a minute to examine the two `if` statements at the end of the file:
```cs
if (total >= 15){
Console.WriteLine("You win!");
}
if (total < 15){
Console.WriteLine("Sorry, you lose.");
}
```
Notice that both `if` statements compare `total` with the same numeric value.
This is the perfect opportunity to use an `else` statement.
Update the two if statements as follows:
```cs
if (total >= 15){
Console.WriteLine("You win!");
} else {
Console.WriteLine("Sorry, you lose.");
}
```
Here, if `total >= 15` is false, then the code block following the `else`
keyword will execute. Since the two outcomes are related opposites, this is a
perfect scenario for the `else` keyword.
Your updated Program.cs file should contain the following code:
```cs
Random dice = new Random();
int roll1 = dice.Next(1, 7);
int roll2 = dice.Next(1, 7);
int roll3 = dice.Next(1, 7);
int total = roll1 + roll2 + roll3;
Console.WriteLine($"Dice roll: {roll1} + {roll2} + {roll3} = {total}");
if ((roll1 == roll2) || (roll2 == roll3) || (roll1 == roll3)){
Console.WriteLine("You rolled doubles! +2 bonus to total!");
total += 2;
}
if ((roll1 == roll2) && (roll2 == roll3)){
Console.WriteLine("You rolled triples! +6 bonus to total!");
total += 6;
}
if (total >= 15){
Console.WriteLine("You win!");
} else {
Console.WriteLine("Sorry, you lose.");
}
```
#### Modify the code to remove the stacking bonus for doubles and triples using nesting
In the previous unit, you saw that a subtle logic bug was introduced into your
application. You can fix that issue by nesting your `if` statements.
Nesting allows you to place code blocks inside of code blocks. In this case,
you'll nest an if and else combination (the check for doubles) inside of
another if statement (the check for triples) to prevent both bonuses from being
awarded.
Modify your code to match the following code listing:
```cs
Random dice = new Random();
int roll1 = dice.Next(1, 7);
int roll2 = dice.Next(1, 7);
int roll3 = dice.Next(1, 7);
int total = roll1 + roll2 + roll3;
Console.WriteLine($"Dice roll: {roll1} + {roll2} + {roll3} = {total}");
if ((roll1 == roll2) || (roll2 == roll3) || (roll1 == roll3)){
if ((roll1 == roll2) && (roll2 == roll3)){
Console.WriteLine("You rolled triples! +6 bonus to total!");
total += 6;
} else {
Console.WriteLine("You rolled doubles! +2 bonus to total!");
total += 2;
}
}
if (total >= 15){
Console.WriteLine("You win!");
} else {
Console.WriteLine("Sorry, you lose.");
}
```
Take a minute to review the nested `if` statements.
The goal is to create an inner `if-else` construct where the two outcomes
are related opposites, and then use the opposing outcomes (if/true and else
/false) to award the bonus points for triples and doubles. To achieve this goal,
you check for doubles in the outer `if` statement, and then for triples in the
inner `if` statement. This pattern ensures that when the inner check for
triples returns `false`, your `else` code block can award the points for doubles.
Coming up, you will "hard code" the results of your three rolls in order to
test your code logic.
Create a blank code line above the line where total is declared and initialized.
To test for a roll of doubles, enter the following code:
```cs
roll1 = 6;
roll2 = 6;
roll3 = 5;
```
Hard coding the three roll variables enables you to test the code without
having to run the application dozens of times.
When your code runs, you should see:
```cs
Dice roll: 6 + 6 + 5 = 17
You rolled doubles! +2 bonus to total!
You win!
```
To test for a roll of triples, update your hard-coded roll variables as follows:
```cs
roll1 = 6;
roll2 = 6;
roll3 = 6;
```
When your code runs, you should see:
```txt
Dice roll: 6 + 6 + 6 = 18
You rolled triples! +6 bonus to total!
You win!
```
#### Use if, else, and else if statements to give a prize instead of a win-lose message
To make the game more fun, you can change the game from "win-or-lose" to awarding fictitious prizes for each score. You can offer four prizes. However, the player should win only one prize:
- If the player scores greater or equal to 16, they'll win a new car.
- If the player scores greater or equal to 10, they'll win a new laptop.
- If the player scores exactly 7, they'll win a trip.
- Otherwise, the player wins a kitten.
Modify the code from the previous steps to the following code listing:
```cs
Random dice = new Random();
int roll1 = dice.Next(1, 7);
int roll2 = dice.Next(1, 7);
int roll3 = dice.Next(1, 7);
int total = roll1 + roll2 + roll3;
Console.WriteLine($"Dice roll: {roll1} + {roll2} + {roll3} = {total}");
if ((roll1 == roll2) || (roll2 == roll3) || (roll1 == roll3)){
if ((roll1 == roll2) && (roll2 == roll3)){
Console.WriteLine("You rolled triples! +6 bonus to total!");
total += 6;
} else {
Console.WriteLine("You rolled doubles! +2 bonus to total!");
total += 2;
}
Console.WriteLine($"Your total including the bonus: {total}");
}
if (total >= 16){
Console.WriteLine("You win a new car!");
} else if (total >= 10){
Console.WriteLine("You win a new laptop!");
} else if (total == 7){
Console.WriteLine("You win a trip for two!");
} else {
Console.WriteLine("You win a kitten!");
}
```
Take a minute to review the updated `if-elseif-else` construct.
The `if`, `else if`, and `else` statements allow you to create multiple
exclusive conditions as Boolean expressions. In other words, when you only
want one outcome to happen, but you have several possible conditions and
results, use as many `else if` statements as you want. If none of the `if` and
`else if` statements apply, the final `else` code block will be executed. The
`else` is optional, but it must come last if you choose to include it.
Use the technique of temporarily hard coding the `roll` variables to test each
message.
### Recap
- The combination of `if` and `else` statements allows you to test for one
condition, and then perform one of two outcomes. The code block for the `if`
will be run when the Boolean expression is `true`, and the code block for the
`else` will be run when the Boolean expression is `false`.
- You can nest `if` statements to narrow down a possible condition. However, you
should consider using the `if`, `else if`, and `else` statements instead.
- Use `else if` statements to create multiple exclusive conditions.
- An `else` is optional, but it must always come last when included.
---
## Exercise
### Complete a challenge activity to apply business rules
Code challenges will reinforce what you've learned and help you gain some
confidence before proceeding.
### Challenge: Improve renewal rate of subscriptions
You've been asked to add a feature to your company's software. The feature is
intended to improve the renewal rate of subscriptions to the software. Your
task is to display a renewal message when a user logs into the software system
and is notified their subscription will soon end. You'll need to add a couple
of decision statements to properly add branching logic to the application to
satisfy the requirements.
### Prepare your coding environment
To create the initial code for this challenge, enter the following code:
```cs
Random random = new Random();
int daysUntilExpiration = random.Next(12);
int discountPercentage = 0;
// Your code goes here
```
Notice that this code will generate a random number with a value of 0 - 11.
The random number is assigned to an integer variable named `daysUntilExpiration`.
You have another integer variable named `discountPercentage` that is initialized
to `0`.
### Review the business rules for this challenge
1. Rule 1: Your code should only display one message.
The message that your code displays will depend on the other five rules. For rules 2-6, the higher numbered rules take precedence over the lower numbered rules.
2. Rule 2: If the user's subscription will expire in 10 days or less, display the message:
```txt
Your subscription will expire soon. Renew now!
```
3. Rule 3: If the user's subscription will expire in five days or less, display the messages:
```txt
Your subscription expires in _ days.
Renew now and save 10%!
```
> Note
Be sure to replace the _ character displayed in the message above with the
value stored in the variable daysUntilExpiration when you construct your
message output.
4. Rule 4: If the user's subscription will expire in one day, display the messages:
```txt
Your subscription expires within a day!
Renew now and save 20%!
```
5. Rule 5: If the user's subscription has expired, display the message:
```txt
Your subscription has expired.
```
6. Rule 6: If the user's subscription doesn't expire in 10 days or less, display nothing.
### Implement your solution code using `if` statements
Your solution must use separate `if` and `if-else` statements to implement the
business rules. The `if-else` statement can include multiple `else if` parts.
1. Create an `if-else` statement that displays a message about when the
subscription will expire.
> Tip
Use an else if to ensure each expiration rule is accounted for.
2. Create a separate `if` statement that displays a discount offer.
The business rules indicate when a discount should be offered.