Controlling Flow and Converting Types

C# - Controlling Flow and Converting Types , ANGULAR WITH CORE .NET AND MVC RAZOR ENGINE

Introduction

This chapter is all about writing code that performs simple operations on variables, makes decisions, repeats blocks of statements, converts variable or expression values from one type to another, handles exceptions, and checks for overflows in number variables.

     This chapter covers the following topics:

  • Operating on variables
  • Understanding selection statements
  • Understanding iteration statements
  • Casting and converting between types
  • Handling exceptions
  • Checking for overflow

Operating on variables


Operators apply simple operations such as addition and multiplication to operands

such as variables and literal values. They usually return a new value that is the result

of the operation that can be assigned to a variable.

>Most operators are binary, meaning that they work on two operands, as shown in the

following pseudocode:



          var resultOfOperation = firstOperand operator secondOperand;


Some operators are unary, meaning they work on a single operand, and can apply

before or after the operand, as shown in the following pseudocode:



          var resultOfOperation = onlyOperand operator;

          var resultOfOperation2 = operator onlyOperand;

Examples of unary operators include incrementors and retrieving a type or its size in

bytes, as shown in the following code:

         int x = 5;
         int incrementedByOne = x++;
         int incrementedByOneAgain = ++x;

         Type theTypeOfAnInteger = typeof(int);
         int howManyBytesInAnInteger = sizeof(int);

Unary operators


Two common unary operators are used to increment, ++, and decrement, --, a number

Binary arithmetic operators

Increment and decrement are unary arithmetic operators. Other arithmetic operators

are usually binary and allow you to perform arithmetic operations on two numbers.

Assignment operators


You have already been using the most common assignment operator, =.

To make your code more concise, you can combine the assignment operator with

other operators like arithmetic operators, as shown in the following code:

                                                       int p = 6;
p += 3; // equivalent to p = p + 3;
p -= 3; // equivalent to p = p - 3;
p *= 3; // equivalent to p = p * 3;
p /= 3; // equivalent to p = p / 3;

Logical operators

Logical operators operate on Boolean values, so they return either true or false.


Conditional logical operators

Conditional logical operators are similar to logical operators, but you use two
symbols instead of one, for example, && instead of &, or || instead of |.

Bitwise and binary shift operators

Bitwise operators effect the bits in a number. Binary shift operators can perform
some common arithmetic calculations much faster than traditional operators.

Miscellaneous operators

nameof and sizeof are convenient operators when working with types. nameof
returns the short name (without namespace) of a variable, type, or member as

a string value, which is useful when outputting exception messages. sizeof returns

the size in bytes of simple types, which is useful for determining efficiency of data

storage.
There are many other operators; for example, the dot between a variable and its
members is called the member access operator and the round brackets at the end of a
function or method name is called the invocation operator, as shown in the following
code:

int age = 47;
// How many operators in the following statement?
string firstDigit = age.ToString()[0];
// There are four operators:
// = is the assignment operator
// . is the member access operator
// () is the invocation operator
// [] is the indexer access operator

Understanding selection statements

Every application needs to be able to select from choices and branch along with different

code paths. The two selection statements in C# are if and switch. You can use it
for all your code, but the switch can simplify your code in some common scenarios such
as when there is a single variable that can have multiple values that each require
different processing.

Branching with the if statement

The if statement determines which branch to follow by evaluating a Boolean
expression. If the expression is true, then the block executes. The else block is
optional, and it executes if the if expression is false. The if statement can be
nested.

if (expression1)
{
// runs if expression1 is true
}
else if (expression2)
{
// runs if expression1 is false and expression2 if true
}
else if (expression3)
{
// runs if expression1 and expression2 are false
// and expression3 is true
}
else
{
// runs if all expressions are false
}

Each if statement's Boolean expression is independent of the others and unlike
switch statements does not need to reference a single value

Why you should always use braces with if statements

As there is only a single statement inside each block, the preceding code could be
written without the curly braces, as shown in the following code:

if (args.Length == 0)
WriteLine("There are no arguments.");
else
WriteLine("There is at least one argument.");

This style of the if statement should be avoided because it can introduce serious
bugs, for example, the infamous #gotofail bug in Apple's iPhone iOS operating
system. For 18 months after Apple's iOS 6 was released, in September 2012, it had a
bug in its Secure Sockets Layer (SSL)  encryption code, which meant that any user
running Safari, the device's web browser, who tried to connect to secure websites,
such as their bank, was not properly secure because an important check was being
accidentally skipped.
You can read about this infamous bug at the following link: https://gotofail.com/.
Just because you can leave out the curly braces, doesn't mean you should. Your code
is not "more efficient" without them; instead, it is less maintainable and potentially
more dangerous.

Pattern matching with the if statement

A feature introduced with C# 7.0 and later is pattern matching. The if statement can
use the is keyword in combination with declaring a local variable to make your code
safer.

1. Add statements to the end of the Main method so that if the value stored in
the variable named o is an int, then the value is assigned to the local variable
named i, which can then be used inside the if statement. This is safer
than using the variable named o because we know for sure that i is an int
variable and not something else, as shown in the following code:

// add and remove the "" to change the behavior
object o = "3";
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!");
}
2. Run the console application and view the results, as shown in the following
output:
o is not an int so it cannot multiply!
3. Delete the double-quote characters around the 2. Run the console application and view the results, as shown in the following
output:
o is not an int so it cannot multiply!
3. Delete the double-quote characters around the "3" value so that the value
stored in the variable named o is an int type instead of a string type.
4. Rerun the console application to view the results, as shown in the following
output:
3 x 4 = 12 value so that the value
stored in the variable named o is an int type instead of a string type.
4. Rerun the console application to view the results, as shown in the following
output:
3 x 4 = 12

Branching with the switch statement

The switch statement is different from the if statement because it compares a single
expression against a list of multiple possible case statements. Every case statement
is related to the single expression. Every case section must end with:
  • The break keyword (like case 1 in the following code),
  • Or the goto case keywords (like case 2 in the following code),
  • Or they should have no statements (like case 3 in the following code).
Let's write some code to explore the switch statements

1. Enter some statements for a switch statement after the if statements that
you wrote previously. You should note that the first line is a label that can
be jumped to, and the second line generates a random number. The switch
statement branches based on the value of this random number, as shown in
the following code:

A_label:
var number = (new Random()).Next(1, 7);
WriteLine($"My random number is {number}");

switch (number)
{
case 1:
WriteLine("One");
break; // jumps to end of switch statement
case 2:
WriteLine("Two");
goto case 1;
case 3:
case 4:
WriteLine("Three or four");
goto case 1;
case 5:
// go to sleep for half a second
System.Threading.Thread.Sleep(500);
goto A_label;
default:
WriteLine("Default");
break;
} // end of switch statement

2. Run the console application multiple times in order to see what happens
in various cases of random numbers, as shown in the following example
output:

bash-3.2$ dotnet run
My random number is 4
Three or four
One
bash-3.2$ dotnet run
My random number is 2
Two
One
bash-3.2$ dotnet run
My random number is 1
One


Pattern matching with the switch statement

Like the if statement, the switch statement supports pattern matching in C# 7.0 and
later. The case values no longer need to be literal values. They can be patterns.
Let's see an example of pattern matching with the switch statement using a folder
path. If you are using macOS, then swap the commented statement that sets the path
variable and replace my username with your user folder name.

1. Add the following statement to the top of the file to import types for working
with input/output:
using System.IO;

2. Add statements to the end of the Main method to declare a string path to
a file, open it as a stream, and then show a message based on what type and
capabilities the stream has, as shown in the following code:

// string path = "/Users/markjprice/Code/Chapter03";
string path = @"C:\Code\Chapter03";
Stream s = File.Open(
Path.Combine(path, "file.txt"), FileMode.OpenOrCreate);
string message = string.Empty;
switch (s)
{
case FileStream writeableFile when s.CanWrite:
message = "The stream is a file that I can write to.";
break;
case FileStream readOnlyFile:
message = "The stream is a read-only file.";
break;
case MemoryStream ms:
message = "The stream is a memory address.";
break;
default: // always evaluated last despite its current position
message = "The stream is some other type.";
break;
case null:
message = "The stream is null.";
break;
}
WriteLine(message);

3. Run the console app and note that the variable named s is declared as a Stream
type so it could be any subtype of stream like a memory stream or file stream.
In this code, the stream is created using the File.Open method, which returns
a file stream and due to the FileMode, it will be writeable, so the result will be
a message that describes the situation, as shown in the following output:
The stream is a file that I can write to.

Understanding iteration statements

Iteration statements repeat a block of statements either while a condition is true or for
each item in a collection. The choice of which statement to use is based on a combination
of ease of understanding to solve the logic problem and personal preference.

Looping with the while statement

The while statement evaluates a Boolean expression and continues to loop while it is
true.

Looping with the do statement

The do statement is like while except the Boolean expression is checked at the
bottom of the block instead of the top, which means that the block always executes at
least once.

Looping with the For statement

The for statement is like while, except that it is more succinct. It combines:

  • An initializer expression, which executes once at the start of the loop.
  • A conditional expression, which that executes on every iteration at the start
    of the loop to check whether the looping should continue.
  • An iterator expression, which that executes on every loop at the bottom of
    the statement.
The for statement is commonly used with an integer counter. Let's explore
some code.
  1. Enter a for statement to output the numbers 1 to 10, as shown in the
    following code:
for (int y = 1; y <= 10; y++)
{
WriteLine(y);
}
     2. Run the console application to view the result, which should be the numbers
        1 to 10.

Looping with the foreach statement

The foreach statement is a bit different from the previous three iteration statements

It is used to perform a block of statements on each item in a sequence, for example,
an array or collection. Each item is usually read-only, and if the sequence structure
is modified during iteration, for example, by adding or removing an item, then an
exception will be thrown.

  1. Type statements to create an array of string variables and then output the
    length of each one, as shown in the following code: 
string[] names = { "Adam", "Barry", "Charlie" };
foreach (string name in names)
{
WriteLine($"{name} has {name.Length} characters.");
}

2.Run the console application and view the results, as shown in the following
output

Adam has 4 characters.
Barry has 5 characters.
Charlie has 7 characters.

Understanding how foreach works internally

Technically, the foreach statement will work on any type that follows these rules:
  1. The type must have a method named GetEnumerator that returns an object.
  2. The returned object must have a property named Current and a method
    named MoveNext
  3. The MoveNext method must return true if there are more items to enumerate
    through or false if there are no more items.
There are interfaces named IEnumerable and IEnumerable<T> that formally define
these rules but technically the compiler does not require the type to implement these
interfaces.

The compiler turns the foreach statement in the preceding example into something
similar to the following pseudocode

IEnumerator e = names.GetEnumerator();
while (e.MoveNext())
{
string name = (string)e.Current; // Current is read-only!
WriteLine($"{name} has {name.Length} characters.");
}

Due to the use of an iterator, the variable declared in a foreach statement cannot be
used to modify the value of the current item.

Casting and converting between types

You will often need to convert values of variables between different types. For
example, data input is often entered as text at the console, so it is initially stored in
a variable of the string type, but it then needs to be converted into a date/time, or
number, or some other data type, depending on how it should be stored and processed.
Sometimes you will need to convert between number types, like between an integer
and a floating-point, before performing calculations.
Converting is also known as casting, and it has two varieties: implicit and explicit.
Implicit casting happens automatically, and it is safe, meaning that you will not lose
any information.

Explicit casting must be performed manually because it may lose information, for
example, the precision of a number. By explicitly casting, you are telling the C#
compiler that you understand and accept the risk.

Wrapping error-prone code in a try block

When you know that a statement can cause an error, you should wrap that statement
in a try block. For example, parsing from text to a number can cause an error. Any
statements in the catch block will be executed only if an exception is thrown by a
statement in the try block. We don't have to do anything inside the catch block.

Comments

Popular posts from this blog

How to disable table row in Angular

How to create XML file dynamically in c#.net?

How to get Array value in Angular ?