Working with C# Iteration Constructs
All programming languages provide ways to repeat blocks of code until a terminating conditions has been met
- for loop
- foreach/in loop
- while loop
- do/while loop
Using the for loop
When you need to iterate over a block of code a fixed number of times, the for statement provides a good deal of flexibility.
for(int i = 0;i<4;i++){
Console.WriteLine("Number is {0}",i);
}Using the foreach loop
The C# foreach keyword allows you to iterate over all items in a container without the need to test for an upper limit. Unlike a for loop, however, the foreach loop will walk the container only in a linear (n+1) fashion. (Thus you cannot go backward through the container, skip every third element).
string[] carTypes = {"Toyota","Mercedes","Ford"};
foreach(string c in carTypes){
Console.WriteLine(c);
}
int myInts = {10,20,30,40};
foreach(int i in myInts){
Console.WriteLine(i);
}
Using Implicit Typing Within foreach Constructs
It's also possible to use implicit typing within a foreach looping construct. As you would expect, the compiler will correctly infer the correct "type of type".
int[] numbers = {10,20,30,40,1,2,3,8};
// LINQ Query
var subset = from i in numbers where i < 10 select i;
foreach(var i in subset){
Console.Write(i);
}
Using the while and do/while Looping Constructs
The while looping construct is useful should you want to execute a block of statements until some terminating condition has been reached. Within the scope of a while loop, you will need to ensure this terminating event is indeed established, otherwise, you will be stuck in an endless loop.
string userIsDone = "";
while(userIsDone.ToLower()!="Yes"){
Console.Write("Are you done [yes] [no] :");
userIsDone = Console.ReadLine();
}
do/while is used when you need to perform some action an undetermined number of times. The difference is that do/while loops are guaranteed to execute the corresponding block of code at least one. In contrast, it is possible that a simple while loop may never execute if the terminating condition is false from the onset.
string userIsDone = "";
do {
Console.Write("Are you done [yes] [no] : ");
userIsDone = Console.ReadLine();
}while(userIsDone.ToLower() != "Yes");
A Quick Discussion About Scope
A scope is created using curl braces.
for(int i = 0;i<=4;i++){
Console.WriteLine("Number is {0}",i);
}
Working with Decision Construct and the Relational/Equality Operators
C# defines 2 simple constructs to alter the flow of your program;
- The if/else statement
- The switch statement
Using the if/else statement
The if/else statement in C# operates only on Boolean expressions, not ad hoc values such as -1 or 0.
Using Equality and Relational Operators
| Equality/Relational Operator | Example Usage | Meaning in Life |
| == | if (age == 30) | Return true only if each expression is the same. |
| != | if ("fos" != myStr) | Returns true only if each expression is different. |
| < | if (bonus < 200) | Returns true if expression A (bonus) is less than expression B (200). |
| > | if (bonus > 200) | Returns true if expression A (bonus) is greater than expression B (200). |
| <= | if (bonus <= 200) | Returns true if expression A (bonus) is less than or equal to expression B (200). |
| >= | if (bonus >= 200) | Returns true if expression A (bonus) is greater than or equal to expression B (200). |
Using if/else with Pattern Matching
New in C# 7.0, pattern matching is allowed in if(else statements. Pattern matching allows code to inspect an object for certain traits and properties and make decisions based on the (non)existance of those properties and traits.
Just know that you can check the type of an object using the "is" keyword.
object testItem1 = 123;
object testItem2 = "Hello";
if (testItem1 is string myStringValue){
Console.WriteLine($"{myStringValue} is a string");
}
if (testItem2 is int myValue2){
Console.WriteLine($"{myValue2} is an int");
}Making Pattern Matching Improvements
Pattern
- Type Patterns : Checks if a variable is a type.
- Parenthesized Patterns : Enforces emphasized the precedence of pattern combinators.
- Conjunctive (and) Patterns : Required both patterns to match.
- Disjunctive (or) Patterns : Required either pattern to match.
- Negated (not) Patterns : Requires a pattern does not match.
- Relational Patterns : Requires input to be less than, less than or equal, greater than, or greater than or equal
- Pattern Combinator : Allows multiple patterns to be used together.
object testItem1 = 123;
Type t = typeof(string);
char c = 'f';
// Type patterns
if (t is Type){
Console.WriteLine($"{t} is a Type");
}
// Relational, Conjunctive, and Disjunctive Patterns
if (c >= 'a' and <= 'z' or >= 'a' and <= 'Z'){
Console.WriteLine($"{c} is a character");
}
// Paranthesized Patterns
if (c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z') or '.' or ','){
Console.WriteLine($"{c} is a character or a separator");
}
// Negative Patterns
if (testItem1 is not string){
Console.WriteLine($"{testItem1} is not a string");
}
if (testItem1 is not null){
Console.WriteLine($"{testItem1} is not null");
}
Using the Conditional Operator (Updated 7.2,9.0)
The conditional operator (?:) also known as the "ternary conditional operator." is a shorthand method of writing a simple if/else statement.
Condition ? first_expression : second_expression;
The condition is the conditional test if the test passes, then the code immediately after the question mark (?) is executed. If the test does not evaluate to true, the code after the colon is executed.
string stringData = "My Textual Data";
Console.WriteLine(stringData.Length > 0 ? "string is greater than 0" : "less than 0");
New in C# 7.2, the conditional operator can be used to return a reference to the result of the condition.
var smallArray = new int[] { 1, 2, 3, 4, 5 };
var largeArray = new int[] { 10, 20, 30, 40, 50 };
int index = 7;
ref int refValue = ref ((index < 45) ? ref smallArray[index] : ref largeArray[index - 5]);
Using Logical Operators
To build complex expressions, C# offers an expected set of logical operators.
| Operator | Example | Meaning in Life |
| && | if (age == 30 && name == "fred") | AND operator. Returns true if all expressions are true. |
| || | if (age == 30 || name == "fred") | OR opreator. Returns true if at least one expression is true. |
| ! | if (!myBool) | Not operator. Returns true if false, or false if true. |
Note : The && and || operators both "short-circuit" when necessary. This means that after a complex expression has been determined to be false, the remaining subexpression will not be checked. If you require all expressions to be tested regardless, you can use the related & and |operators.
Using the switch Statement
The "switch" statement allows you to handle program flow based on a predefined set of choices.
string langChoice = Console.ReadLine();
int n = int.Parse(langChoice);
switch(n){
case 1:Console.WriteLine("Good choice, C#");break;
case 2:Console.WriteLine("VB: OOP, multithreading");break;
default:Console.WriteLine("Well... Good Luck");break;
}
One nice feature of the C# switch statement is that you can evaluate string data in addition to numeric data. In fact, all versions of C# can evaluate char, string, bool, int, long, and enum data types.
string langChoice = Console.ReadLine();
switch(langChoice.ToUpper()){
case "C#": Console.WriteLine("Good choice, C#");break;
case "VB": Console.WriteLine("VB: OOP, multithreading");break;
default: Console.WriteLine("Good Luck...");break;
}
It is also possible to switch an enumeration data type. Enum, the C# enum keyword allows you to define a custom set of name-value pairs.
DayOfWeek favDay;
try{
favDay = (DayOfWeek) Enum.Parse(typeof(DayOfWeek),Console.ReadLine());
}catch(Exception e){
Console.WriteLine(e.Message);
return;
}
switch(favDay){
case DayOfWeek.Sunday: Console.WriteLine("Pazar");break;
default: Console.WriteLine("Unknown day");break;
}The switch statement also supports using goto to exit a case condition and execute another case statement. While this is supported, it is pretty universally thought of as an anti-pattern and not generally used.
var foo = 5;
switch(foo){
case 1:
// do something
goto case 3;
case 3:
// do something
goto default;
default:
// do something.
break;
}
Performing switch Statement Pattern Matching (New 7.0, Updated 9.0)
Prior to C# 7, match expressions in switch statements were limited to comparing a variable to constant values, sometimes referred to as the "constant pattern". In C# 7, switch statements can also employ the "type pattern", where case statements can evaluate the type of the variable being "checked" and "case" expressions are no longer limited to constant values. The rule is that each case statement must be terminated with a return or break still applies; however, goto statements are not supported using the type pattern.
string userChoice = Console.ReadLine();
object choice;
// This is a standard constant pattern switch statement example.
switch(userChoice) {
case "1": choice = 5;break;
case "2": choice = "Hi";break;
case "3": choice = 2.5M;break;
default: choice = 5; break;
}
// This is new the pattern matching switch statement.
switch(choice){
case int i: Console.WriteLine("your choice is an integer");break;
case string s: Console.WriteLine("your choice is a string");break;
case decimal d: Console.WriteLine("your choice is a decimal")break;
default: Console.WriteLine("your choice is something else");break;
}
In addition to evaluation on the type of the match expression, when clauses can be added to the case statement to evaluate conditions on the variable.
Console.WriteLine("1 [C#], 2 [VB] : ");
object langChoice = Console.ReadLine();
var choice = int.TryParse(langChoice.ToString(),out int c) ? c : langChoice;
switch(choice){
case int i when i == 2:
case string s when s.Equals("VB",StringComparison.OrdinalIgnoreCase):
Console.WriteLine("VB OOP;Multithreading...");break;
case int i when i == 1:
case string s when s.Equals("C#",StringComparison.OrdinalIgnoreCase):
Console.WriteLine("C# is a good choice");break;
default:
Console.WriteLine("Good luck...");break;
}
Using Switch Expressions (New 8.0)
New in C# 8, are switch expressions, allowing the assignment of a variable in a concise statement.
static string FromRainbowClassics(string color){
switch(color){
case "Red": return "#FF0000";
case "Blue": return "#FF21000";
default: return "#FFFFFF";
}
}
static string FromRainbowClassics(string color){
return color switch {
"Red" => "#FF0000",
"Blue" => "#FF21000";
_ => "#FFFFFF";
};
}