Chapter 3: Controlling Flow, Converting Types, and Handling Exceptions [Flashcarder]
What topics are covered in this, 3rd, chapter?
The chapter covers writing code that performs operations on variables,
making decisions,
pattern matching,
repeating statements or blocks,
working with arrays,
type casting and converting,
exception handling, and checking for overflow.
What are binary operators, and how do they work?
Binary operators work on two operands and return a new value that is the result of the operation.
For example, x + y
and x * y
are binary operators.
What are unary operators, and how do they work?
Unary operators work on a single operand and can be applied before or after the operand.
What are examples of unary operators in C#?
Examples of unary operators include the increment operators (++x, x++), the typeof operator to get a type, the nameof operator to get a variable name, and the sizeof operator to get the size of a type.
What is a ternary operator in C#?
A ternary operator works with three operands.
In C#, the conditional operator ?: is an example of a ternary operator.
It evaluates a Boolean expression and returns one of two values depending on whether the expression is true or false.
Why might experienced C# developers prefer using ternary operators over if statements?
Experienced C# developers might prefer ternary operators because they are concise and can result in cleaner code once you are familiar with reading them.
What is the difference between the postfix ++ operator and the prefix ++ operator in C#?
The postfix ++ operator increments the value after it is used in an assignment.
The prefix ++ operator increments the value before it is used.
In the code snippet int a = 3; int b = a++;, what are the values of a and b after execution?
a will have a value of 4, and
b will have a value of 3.
In the code snippet int c = 3; int d = ++c;, what are the values of c and d after execution?
Both c and d will have a value of 4.
What is the recommended practice for using the increment (++) and decrement (- -) operators in C# to avoid confusion?
The recommended practice is to avoid combining the use of increment (++) and decrement (- -) operators with the assignment operator (=).
Instead, perform these operations as separate statements to enhance code clarity and maintainability.
What do binary arithmetic operators do in C# programming?
Binary arithmetic operators perform arithmetic operations on two numbers.
Common binary arithmetic operators includeL
addition (+),
subtraction (-),
multiplication (*),
division (/), and
modulus (%).
How does C# calculate the modulus (%) operation and what is the result for e % f when e is 11 and f is 3?
The modulus operation calculates the remainder after division of one number by another.
For e % f with e as 11 and f as 3, the result is 2, representing the remainder when 11 is divided by 3.
What difference does it make to the division operation in C# when the first operand is a floating-point number like g = 11.0?
When the first operand is a floating-point number, the division operation returns a floating-point result.
For instance, dividing g = 11.0 by f = 3 yields approximately 3.6666666666666665, reflecting the actual quotient without truncating to an integer.
What does the assignment operator += do in C#?
The += operator adds the right operand to the left operand and assigns the result to the left operand.
For example, p += 3 is equivalent to p = p + 3.
Explain the function of the -= operator in C#.
The -= operator subtracts the right operand from the left operand and assigns the result back to the left operand.
For instance, p -= 3 means p = p - 3.
Describe the use of *= in C#.
The *= operator multiplies the left operand by the right operand and assigns the result to the left operand.
p *= 3 translates to p = p * 3.
How does the /= operator work in C#?
The /= operator divides the left operand by the right operand and assigns the result to the left operand.
p /= 3 is equivalent to p = p / 3.
What is the purpose of the null-coalescing operator ?? in C#?
The ?? operator returns the left-hand operand if it is not null; otherwise, it returns the right-hand operand.
For example, int maxLength = authorName?.Length ?? 30
assigns maxLength the value of authorName.Length if authorName is not null, or 30 if authorName is null.
How does the null-coalescing assignment operator ??= function in C#?
The ??= operator assigns the right-hand value to the left-hand operand only if the left-hand operand is null.
For example, authorName ??= "unknown"
assigns “unknown” to authorName if authorName is currently null.
What is the result of the AND logical operator when both operands are true?
True
What is the result of the AND logical operator when one operand is true and the other is false?
False
What is the result of the OR logical operator when both operands are true?
True
What is the result of the OR logical operator when one operand is true and the other is false?
True
What is the result of the OR logical operator when both operands are false?
False
What is the result of the XOR logical operator when both operands are true?
False
What is the result of the XOR logical operator when one operand is true and the other is false?
True
What is the result of the XOR logical operator when both operands are false?
False
What do conditional logical operators in C# do differently from their non-conditional counterparts?
Conditional logical operators (&& and ||) perform short-circuiting, meaning they do not evaluate the second operand if the first operand determines the result, which can improve efficiency but may lead to skipped function calls if used with functions that have side effects.
How does the ‘&&’ operator behave when the first operand is false?
The ‘&&’ operator will not evaluate the second operand if the first operand is false because the overall expression cannot be true, thus short-circuiting the evaluation.
What is the purpose of the ‘||’ operator in conditional logical operations?
The ‘||’ operator will not evaluate the second operand if the first operand is true because the overall expression will be true regardless of the second operand, thereby short-circuiting further evaluation.
What is demonstrated by using functions with conditional logical operators in C#?
Using functions with conditional logical operators shows how short-circuiting can prevent the function from executing if the preceding condition already determines the result, potentially leading to efficiencies or missed side effects depending on the function’s actions.
What is a good practice when using conditional logical operators with functions in C#?
It is good practice to avoid using conditional logical operators with functions that have side effects, as these functions may not execute if short-circuiting occurs, potentially leading to unexpected behavior or bugs.
How can the ‘&’, ‘&&’, ‘|’, and ‘||’ operators differ when applied in a program?
The ‘&’ and ‘|’ operators evaluate both operands regardless of their values,
while the ‘&&’ and ‘||’ operators may only evaluate the first operand if it is sufficient to determine the result (true for ‘||’, false for ‘&&’), demonstrating short-circuiting behavior.
What are bitwise operators and what do they compare?
Bitwise operators compare the bits in the binary representation of a number, where each bit (0 or 1) is compared individually to the bit in the same column.
What are binary shift operators used for in programming?
Binary shift operators are used to perform common arithmetic calculations much faster than traditional operators, such as multiplying by a factor of 2.
How do the AND, OR, and XOR bitwise operators function between two integers x = 10 and y = 6?
AND (&): Compares each bit of x with y, and results in 1 if both bits are 1, otherwise 0.
Example: x & y results in 2 (00000010 in binary).
OR (|): Compares each bit of x with y, and results in 1 if at least one of the bits is 1.
Example: x | y results in 14 (00001110 in binary).
XOR (^): Compares each bit of x with y, and results in 1 only if the bits are different.
Example: x ^ y results in 12 (00001100 in binary).
What are the effects of the left-shift («) and right-shift (») operators on integers?
Illustrate with x = 10 and y = 6.
Left-shift («): The left-shift operator shifts bits to the left, effectively multiplying the integer by 2 for each shift.
For example, shifting x = 10 (1010 in binary) by 3 bits (x «_space;3) results in 80 (01010000 in binary).
Right-shift (»): The right-shift operator shifts bits to the right, effectively dividing the integer by 2 for each shift.
For example, shifting y = 6 (0110 in binary) by 1 bit (y»_space; 1) results in 3 (0011 in binary).
Explain the difference between bitwise and logical operators using the & and | symbols.
When operating on integer values, the & and | symbols are bitwise operators, comparing each corresponding bit of their operands.
When used with Boolean values like true and false, they act as logical operators, determining the truth or falsehood through logical conjunction or disjunction, respectively.
What does the nameof operator return in C#?
The nameof operator returns the short name (without the namespace) of a variable, type, or member as a string value.
What is the purpose of the sizeof operator in C#, and does it require an unsafe code block?
The sizeof operator returns the size in bytes of simple types.
It typically requires an unsafe code block, but for value types with a C# alias, like int and double, the sizes are hardcoded as constants by the compiler, so no unsafe block is needed.
What operators are demonstrated in the expression: char firstDigit = age.ToString()[0];
?
Four operators are demonstrated:
= (assignment operator),
. (member access operator),
() (invocation operator), and
[] (indexer access operator).
How do if and switch selection statements differ in their application?
If statements are used for branching based on Boolean expressions, potentially with multiple else if branches.
Switch statements simplify code when a single variable may have multiple values that each require different processing.
What are the risks of omitting curly braces in if statements?
Omitting curly braces in if statements can introduce serious bugs, as demonstrated by the #gotofail bug in Apple’s iOS, where an important SSL encryption check was accidentally skipped, compromising security.
What is pattern matching in C# 7, and how does it enhance safety in conditional statements?
Pattern matching in C# 7 allows for the use of the is keyword along with a type check and local variable declaration directly in an if statement’s condition.
This ensures that the variable used inside the block is safely of the specified type, enhancing code safety and readability by avoiding invalid operations on wrongly typed variables.
How can you use pattern matching with the if statement to check and cast types simultaneously?
You can use the is keyword followed by a type and a new variable name.
For example, if (o is int i)
checks if o is an int and assigns it to i if true. This allows i to be used within the scope of the if statement safely as an integer.
Demonstrate an example of pattern matching in a conditional check where an object needs to be identified as an integer.
object o = "3"; // initially a string int j = 4; if (o is int i) { WriteLine($"{i} x {j} = {i * j}"); } else { WriteLine("o is not an int so it cannot multiply!"); }
Change o to an integer to see multiplication in action,
e.g., o = 3; then i * j will execute.
What is required at the end of every case section in a switch statement?
Each case section must end with a keyword such as:
‘break’,
‘goto case’,
have no statements,
‘goto a named label’,
‘return’ to exit the function.
How does a switch statement in C# compare values?
A switch statement compares a single expression against a list of multiple possible cases, where each case represents a potential match to the expression’s value.
What is the purpose of the ‘goto case’ keyword in a switch statement?
The ‘goto case’ keyword is used to jump to another case within the same switch statement.
When should the ‘goto’ keyword be used in a switch statement and what is the general opinion on using it?
The ‘goto’ keyword can jump to another case or a named label within a switch statement and should be used sparingly as it is generally frowned upon by most programmers due to potential complexity it adds to the code.
How does the Random.Shared.Next method work in C#?
It generates a pseudo-random number within a specified range, where the lower bound is inclusive and the upper bound is exclusive.
Since .NET 6, the Shared instance of Random is thread-safe and can be used concurrently from any thread.
What happens if none of the case values match the switch expression?
The ‘default’ case executes if present.
If there is no matching case and no default, nothing in the switch executes.
Can you explain the use of labels in switch statements with an example?
In switch statements, labels like ‘A_label’ can be targeted by ‘goto’ commands from a case.
For example, ‘goto A_label;’ will jump execution to the point marked by ‘A_label:’.
What keyword is used in C# 7 and later to enhance the switch statement with pattern matching?
The case keyword can be used with patterns, not just literal values, to enhance the switch statement for pattern matching in C# 7 and later.
How can a local variable be declared and assigned within a switch case statement for safe use in C# 7 and later?
You can declare and assign a local variable directly within a case statement of a switch statement using pattern matching.
This approach ensures that the variable is safely scoped and only accessible within the relevant case block.
switch (obj) { case string s: Console.WriteLine($"String: {s}"); break;
What is the purpose of the when keyword in a switch case statement in C# 7 and later?
The when keyword is used for more specific pattern matching within a case statement, allowing conditions to be specified for the pattern.
Provide an example of using the when keyword in a switch case statement for pattern matching.
case Cat fourLeggedCat when fourLeggedCat.Legs == 4:
checks if an object of type Cat has exactly four legs.
How does pattern matching with the switch statement handle null values in the list of cases?
The switch statement can include a case null: to handle cases where the variable being checked is null.
What is the difference between the traditional and property pattern-matching syntax in C# 7 and later?
Traditional Pattern Matching (C# 7):
- Checks: Type of an object.
- Usage: Type-safe casting within switch
and is
expressions.
- Example:
if (obj is Person p) { Console.WriteLine($"Person: {p.Name}, Age: {p.Age}"); }
Property Pattern Matching (C# 8+)
- Checks: Type and properties of an object.
- Usage: More detailed checks within switch
and is
expressions.
- Example:
if (obj is Person { Age: >= 18 }) { Console.WriteLine("Found an adult person"); }
Key Differences:
- Traditional: Focuses on type checks.
- Property: Focuses on both type and property checks for more detailed matching.
How is the default case handled in a switch statement when pattern matching in C#?
The default case is evaluated last and typically handles any cases that do not match the earlier specific patterns.
What symbol is used in switch expressions to represent the default case, and what is its purpose?
The underscore (_) character is used as a discard in switch expressions to represent the default return value when none of the specified cases match.
How can switch expressions handle different subtypes and properties of a class in C#?
Switch expressions can utilize pattern matching with conditions to return specific strings based on the subtype and attributes of objects, such as different animal types in a class hierarchy (e.g., Cat and Spider with attributes like IsDomestic and IsPoisonous).
What is the output behavior of switch expressions compared to traditional switch statements when applied in similar conditions?
The output of switch expressions is identical to that of switch statements, ensuring the same runtime behavior but with more concise and readable code.
What is an array in C# and how is it commonly indexed?
An array in C# is a data structure used to store multiple values of the same type.
The most common type of array in .NET is the single-dimensional zero-indexed array, which uses the normal [ ] syntax.
How do you declare a single-dimensional array to store string values in C#?
To declare a single-dimensional array of string values in C#, you can use the declaration string[ ] names;, where names can reference any size array of strings.
How do you initialize an array with a fixed size and assign values to it in C#?
You initialize an array in C# by specifying its size and assigning values to its indices, as follows:
int[] numbers = new int[5]; // Initialize array with size 5 numbers[0] = 10; numbers[1] = 20; numbers[2] = 30; numbers[3] = 40; numbers[4] = 50;
How do you iterate through the elements of an array in C#?
To iterate through an array in C#, use a for or foreach loop.
For example:
for (int i = 0; i < names.Length; i++) { WriteLine($"{names[i]} is at position {i}."); }
What is an alternative way to declare and initialize an array in C#?
An alternative way to declare and initialize an array in C# is by using array initializer syntax.
For example:string[] names2 = { "Kate", "Jack", "Rebecca", "Tom" };
Are arrays in C# always zero-indexed?
While the most common type of array in C#, the szArray, is zero-indexed,
.NET also supports multi-dimensional arrays (mdArray) which do not have to have a lower bound of zero.
How do you declare a two-dimensional array in C#?
A two-dimensional array in C# can be declared with the syntax: string[,] grid1;
where [,] indicates it’s a two-dimensional array.
What is the syntax for initializing a two-dimensional array with predefined values in C#?
A two-dimensional array can be initialized with predefined values using the syntax:
string[,] grid1 = { {"Alpha", "Beta", "Gamma", "Delta"}, {"Anne", "Ben", "Charlie", "Doug"}, {"Aardvark", "Bear", "Cat", "Dog"} };
How can you discover the lower and upper bounds of a two-dimensional array in C#?
Use the GetLowerBound() and GetUpperBound() methods.
For example, grid1.GetLowerBound(0)
returns the lower bound of the first dimension.
How do you iterate through all elements of a two-dimensional array in C#?
Use nested for loops based on the array’s bounds.
For example:
for (int row = 0; row <= grid1.GetUpperBound(0); row++) { for (int col = 0; col <= grid1.GetUpperBound(1); col++) { WriteLine($"Row {row}, Column {col}: {grid1[row, col]}"); } }
How do you declare and allocate memory separately for a two-dimensional array in C#?
Declare the array and allocate memory as separate actions, e.g., string[,] grid2 = new string[3,4];
for declaration and memory allocation.
When declaring the size of a multi-dimensional array, what does the dimension size represent?
The dimension size represents the number of items each dimension can hold.
For new string[3,4];
, the first dimension can hold 3 items (indices 0 to 2), and
the second dimension can hold 4 items (indices 0 to 3).
What is a jagged array in C#?
A jagged array, also known as an “array of arrays,” is a structure in C# where each element is an array that can have different lengths, allowing for a multi-dimensional array with variable row sizes.
How do you declare and initialize a jagged array in C#?
You declare and initialize a jagged array by specifying each array within the main array.
Example:
string[][] jagged = { new[] { "Alpha", "Beta", "Gamma" }, new[] { "Anne", "Ben", "Charlie", "Doug" }, new[] { "Aardvark", "Bear" } };
How do you find the upper bound of a jagged array and its sub-arrays in C#?
Use the GetUpperBound(0) method on the jagged array to get the upper bound of the array of arrays, and apply the same method to each sub-array to find their respective upper bounds.
How do you iterate through all elements of a jagged array in C#?
Use nested for loops, accessing each sub-array and then each element within:
for (int row = 0; row <= jagged.GetUpperBound(0); row++) { for (int col = 0; col <= jagged[row].GetUpperBound(0); col++) { WriteLine($"Row {row}, Column {col}: {jagged[row][col]}"); } }
What is a practical scenario for using jagged arrays in C#?
Jagged arrays are ideal when dealing with data structured in rows that vary in length, such as data from different sources where each source may provide a different number of elements.