As you write more and more sophisticated programs, creating lines of code that have to execute one line after another in a set sequence will no longer be sufficient. That's where program flow comes in.
In the Hello World! program from the last chapter, we said hello to the world. Wouldn't it be nice to be a bit more specific - like saying hello to an actual person? 🙋🏽🙋🏻♂️
Display more specific information if it is available
When starting the program, you may not know the name of a user. So what about something like:
If we know the person's name, display it.
Else keep saying hello to the entire world.
This is what conditions are all about.
How do we get to know the person's name in the first place?
Let's go back to the very first statement that a program executes - the Main
function’s signature:
public static void Main(string[] args)
Did you notice the string[] args
inside the ()
? We have an args
variable defined with the type string[]
, which is an array of string
. What that means is that the Main
function is capable of receiving arguments that you can use when the program is started.
The second phase is where you send arguments to your program. Instead of the class name containing the Main
method, you can provide other arguments, separated with a space. For example, HelloWorld.exe Esther.
After the name of the class, we added the "Esther" string. When the program starts, this string is contained in the args
array that is part of the main function's signature. However, our original code does not make use of it. We need to change it to:
Check if the
args
array contains a value (TheLength
property provided by arrays may be our friend here).If it does, call the
SayHelloTo
method with the contained value.Else, keep calling the method with the "World " string.
Here is the actual code:
using System;
namespace Conditions
{
/// <summary>
/// This displays:
/// - a personalized Hello message if an argument has been sent when running the program
/// - The traditional "Hello world!" message if not
/// </summary>
/// <remarks>Created by the OpenClassrooms Education Team</remarks>
public class ConditionalHello
{
/// <summary>
/// This is where the program starts
/// </summary>
/// <param name="args">arguments sent on the command line</param>
public static void Main(string[] args)
{
if (args.Length == 1)
{
SayHelloTo(args[0]);
}
else
{
SayHelloTo("world");
}
}
/// <summary>
/// Displays a hello message to the provided recipient
/// </summary>
/// <param name="recipient">Who to say hello to</param>
private static void SayHelloTo(string recipient)
{
Console.WriteLine("Hello " + recipient + "!");
}
}
}
Try it out for yourself!
Ready to get started? To access the exercise, click this link.
It works! Let's see how that conditional if statement really works.
Test your conditions with booleans
In C#, to validate a condition, you use a special data type called Boolean
. A variable of the Boolean
type can hold only two values: true
or false
. A Boolean
is the simplest data type.
The alias for the Boolean
class is bool
.
In C#, boolean types use true/false pairs. To declare a boolean variable, specify its type as bool
. Let's declare a couple of boolean variables:
bool theCourseIsExcellent = true;
bool theAuthorIsHumble = false;
Makes sense, doesn't it? 😉
The condition that is expressed inside the ()
after the if
keyword must resolve to a bool
. That condition can be expressed as:
A
true
orfalse
value. For instance,if(true)
.A variable of type
bool
. For instance,if(myVar)
wheremyVar
is of typebool
.An expression that resolves to a boolean value. That expression can be as simple as the result of a method call.
For instance:
string weather = "The weather is good";
weather.StartsWith("The weather"); // -> true
StartsWith
is a method from the String
class that returns true
if this string starts with the specified prefix. It can therefore be used as a condition.
To produce a bool
, you can also use comparison operators.
Comparison operators
As the name suggests, comparison operators are used to compare two values. There are six of them:
==
Equal to (exactly the same)!=
Not equal to (different in any way)<
Less than<=
Less than or equal to>
Greater than>=
Greater than or equal to
Here are some examples using numeric comparison:
2 == 2 // -> true
2 == 3 // -> false
4 != 4 // -> false
4 != 5 // -> true
1 < 2 // -> true
1 < 1 // -> false
1 <= 1 // -> true
3 > 4 // -> false
5 > 4 // -> true
5 >= 4 // -> true
Like any other result, it can be assigned to a variable. For instance:
int age = 15;
if(age >= 21)
{
// Do something only of age if at least 21
}
Finally, you may want to have more complicated conditions, where the decision depends on the result of a combination of different expressions. This is where you will use logical operators.
Logical operators
These operators allow you to combine boolean values: either specific boolean values or results of expressions. There are three of them:
&&
logical AND
The result is true only when all the participating parts are true.
Example: The result ofexpression1 && expression2
will be true only ifexpression1
is true ANDexpression2
is also true.||
logical OR
The result is true when at least one of the participating parts is true.
Example: The result ofexpression1 || expression2
will be true ifexpression1
is true ORexpression2
is true. It will also be true if both expressions are true!!
logical NOT
It simply inverts the given expression.
Example: The result of!expression1
is true whenexpression1
is false; the result is false whenexpression1
is true.
Here are some examples:
true && true // true
true && false // false
false && false // false
true || false // true
true || true // true
false || false // false
!true // false
!false // true
The same rules apply when more than two expressions are chained together:
true && true && true // true
true && true && false // false
true || false || false// true
false || false || false// false
Like with numeric operators, the logical operators respect the priority of operations - the inversion operator !
comes first, then AND operator &&
and, finally, OR operator ||
. For example:
false || true && true // true
!false && true || false // true
As with numeric operators, use parentheses ()
to change the order:
(true && false) || true // true
!(true && false || !true) // true
To reinforce what you've learned, try to calculate the result of following expressions:
!true && false
!(true && false)
4 < 3 || 4 >= 4
(!(1 == 2) || 3 != 3) && 35 > 34
To summarize: The general form of a conditional statement in C# is if (condition)
where the condition is either a boolean value, a variable of type boolean, or the result of any expression that produces a boolean value.
In the Hello World! example, we have defined an alternative. What if you want to make more complex decisions, based on several possible values?
Manage a chain of conditions
We've personalized our welcome message, but what if you want use more than one first name?
One possibility is to create a chain of conditions. Here is the general form:
if (condition1)
{
// instructions
}
else if (condition2)
{
// instructions
}
else
{
// instructions
}
Using the Hello World! example, you could send two strings after the class name when running the program. That would mean that the args
array would contain two elements. You could then send a string containing the concatenation of those two strings to the SayHelloTo
function:
public static void Main(string[] args)
{
if (args.Length == 1)
{
SayHelloTo(args[0]);
}
else if (args.Length == 2)
{
SayHelloTo(args[0] + "-" + args[1]);
}
else
{
SayHelloTo("world");
}
}
In this example, the chain evaluates the different values of one particular condition (the size of the args
array). In that case, C# provides a specific construct that only does the evaluation once: the switch
statement.
The switch statement
There are some circumstances when you have a longer set of conditions to go through, and only one can be true
within the sequence. In this case, it's more convenient to use the switch technique. Switch uses what's called cases to compare some value to and make a decision whether an associated block of code needs to be executed. Let's rewrite our if/else if/else example using a switch:
public static void Main(string[] args)
{
switch(args.Length)
{
case 0: // no argument has been sent
SayHelloTo("world");
break;
case 1: // user has provided one argument on the terminal
SayHelloTo(args[0]);
break;
case 2: // user has provided 2 arguments
SayHelloTo(args[0] + "-" + args[1]);
break;
default: // user has provided more than we can manage!
Console.WriteLine("Sorry, I don't know how to manage more than 2 names!");
break;
}
}
With the switch
statement:
The conditional expression
args.Length
is evaluated only once.Each case compares the result of the expression with a specific value.
By default, once a case is evaluated to
true
, all cases below are also evaluated (that's cascading). To prevent this, end each case with abreak
statement.The
default
clause at the end deals with all cases where the result of the expression does not match any case.
The switch statement makes your intent clearer than a chain of if/else, and allows you to evaluate the condition only once. This is cool. 😎 But there's always more available! There's also the enumerations data type.
Use the enum type
Enumerations are a list of predefined cases that help during development. They improve code readability and decrease chance of errors. Let's look at an example where we define all possible directions (north, east, south, west) in an enum, and make use of them in a switch
. Since switch
needs to cover all the possible cases, we can use two approaches.
The first one is listing all the enum cases in switch
so that we don't have to use the default clause:
public class MyDirection
{
/// <summary>
/// Enumerate all possible directions
/// </summary>
enum Direction
{
north,
east,
south,
west
}
/// <summary>
/// Find the north
/// </summary>
public static void Main(string[] args)
{
Direction direction = Direction.north;
switch (direction)
{
case Direction.north:
Console.WriteLine("You are heading north");
break;
case Direction.east:
Console.WriteLine("You are heading east");
break;
case Direction.south:
Console.WriteLine("You are heading south");
break;
case Direction.west:
Console.WriteLine("You are heading west");
break;
}
}
}
In this case, we are covering all directions, so we don't need a default
case.
We can alternatively define a use case where we should only be heading north:
public static void Main(string[] args)
{
Direction direction = Direction.north;
switch (direction)
{
case Direction.north:
Console.WriteLine("You are heading north");
break;
default:
Console.WriteLine("You are lost!");
break;
}
}
Try it out for yourself!
Ready to get started? To access the exercise, click this link.
Let's recap!
Conditions let you execute a block of code only when a provided a
bool
value, variable, or expression evaluates totrue
.A way to provide values to a program is by sending arguments on the command line. Those arguments are made available to the
Main
function inside theargs
array.Conditional expressions make use of boolean arithmetic including comparison operators and logical operators.
You can evaluate multiple conditions by chaining if/else if/else statements.
The
switch
statement is a cleaner way to execute based on different possible values of a particular condition.Enumerations let you define a set of possible values to make your code even more clean.
In the next chapter, you will learn another way to manage the flow of your application: loops.