mirror of
https://github.com/markjprice/cs11dotnet7.git
synced 2025-12-06 05:32:03 +01:00
583 lines
10 KiB
Plaintext
583 lines
10 KiB
Plaintext
#!markdown
|
|
|
|
# Chapter 3 - Controlling Flow and Converting Types
|
|
|
|
#!markdown
|
|
|
|
The following code cell statically imports the Console class so that we can call the `WriteLine` method anywhere.
|
|
|
|
#!csharp
|
|
|
|
using static System.Console;
|
|
|
|
#!markdown
|
|
|
|
# Operating on variables
|
|
|
|
#!markdown
|
|
|
|
## Exploring unary operators
|
|
|
|
#!csharp
|
|
|
|
int a = 3;
|
|
int b = a++;
|
|
WriteLine($"a is {a}, b is {b}");
|
|
|
|
int c = 3;
|
|
int d = ++c; // increment c before assigning it
|
|
WriteLine($"c is {c}, d is {d}");
|
|
|
|
#!markdown
|
|
|
|
## Exploring binary arithmetic operators
|
|
|
|
#!csharp
|
|
|
|
int e = 11;
|
|
int f = 3;
|
|
WriteLine($"e is {e}, f is {f}");
|
|
WriteLine($"e + f = {e + f}");
|
|
WriteLine($"e - f = {e - f}");
|
|
WriteLine($"e * f = {e * f}");
|
|
WriteLine($"e / f = {e / f}");
|
|
WriteLine($"e % f = {e % f}");
|
|
|
|
double g = 11.0;
|
|
WriteLine($"g is {g:N1}, f is {f}");
|
|
WriteLine($"g / f = {g / f}");
|
|
|
|
#!markdown
|
|
|
|
## Exploring logical operators
|
|
|
|
#!csharp
|
|
|
|
bool a = true;
|
|
bool b = false;
|
|
WriteLine($"AND | a | b ");
|
|
WriteLine($"a | {a & a,-5} | {a & b,-5} ");
|
|
WriteLine($"b | {b & a,-5} | {b & b,-5} ");
|
|
WriteLine();
|
|
WriteLine($"OR | a | b ");
|
|
WriteLine($"a | {a | a,-5} | {a | b,-5} ");
|
|
WriteLine($"b | {b | a,-5} | {b | b,-5} ");
|
|
WriteLine();
|
|
WriteLine($"XOR | a | b ");
|
|
WriteLine($"a | {a ^ a,-5} | {a ^ b,-5} ");
|
|
WriteLine($"b | {b ^ a,-5} | {b ^ b,-5} ");
|
|
|
|
#!markdown
|
|
|
|
## Exploring conditional logical operators
|
|
|
|
#!csharp
|
|
|
|
private static bool DoStuff()
|
|
{
|
|
WriteLine("I am doing some stuff.");
|
|
return true;
|
|
}
|
|
|
|
#!csharp
|
|
|
|
WriteLine($"a & DoStuff() = {a & DoStuff()}");
|
|
WriteLine($"b & DoStuff() = {b & DoStuff()}");
|
|
|
|
#!csharp
|
|
|
|
WriteLine($"a && DoStuff() = {a && DoStuff()}");
|
|
WriteLine($"b && DoStuff() = {b && DoStuff()}");
|
|
|
|
#!markdown
|
|
|
|
## Exploring bitwise and binary shift operators
|
|
|
|
#!csharp
|
|
|
|
int a = 10; // 0000 1010
|
|
int b = 6; // 0000 0110
|
|
WriteLine($"a = {a}");
|
|
WriteLine($"b = {b}");
|
|
WriteLine($"a & b = {a & b}"); // 2-bit column only
|
|
WriteLine($"a | b = {a | b}"); // 8, 4, and 2-bit columns
|
|
WriteLine($"a ^ b = {a ^ b}"); // 8 and 4-bit columns
|
|
|
|
#!markdown
|
|
|
|
## Miscellaneous operators
|
|
|
|
#!csharp
|
|
|
|
int age = 47;
|
|
|
|
// How many operators in the following statement?
|
|
char 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
|
|
|
|
#!markdown
|
|
|
|
# Understanding selection statements
|
|
|
|
#!markdown
|
|
|
|
## Branching with the if statement
|
|
|
|
#!csharp
|
|
|
|
string password = "ninja";
|
|
|
|
if (password.Length < 8)
|
|
{
|
|
WriteLine("Your password is too short. Use at least 8 characters.");
|
|
}
|
|
else
|
|
{
|
|
WriteLine("Your password is strong.");
|
|
}
|
|
|
|
#!markdown
|
|
|
|
## Pattern matching with the if statement
|
|
|
|
#!csharp
|
|
|
|
// 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!");
|
|
}
|
|
|
|
#!markdown
|
|
|
|
## Branching with the switch statement
|
|
|
|
#!csharp
|
|
|
|
int 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: // multiple case section
|
|
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
|
|
|
|
WriteLine("After end of switch");
|
|
A_label:
|
|
WriteLine($"After A_label");
|
|
|
|
#!markdown
|
|
|
|
## Pattern matching with the switch statement
|
|
|
|
#!csharp
|
|
|
|
using System.IO;
|
|
|
|
#!markdown
|
|
|
|
`ReadKey` is not supported in .NET Interactive Notebooks. To simulate the user pressing R or W, the following code instantiates a ConsoleKeyInfo object that represents the R or W key being pressed.
|
|
|
|
#!markdown
|
|
|
|
Comment and uncomment the appropriate path depending on your OS.
|
|
|
|
#!csharp
|
|
|
|
//string path = "/Users/markjprice/Code/Chapter03";
|
|
string path = @"C:\Code\Chapter03";
|
|
|
|
Write("Press R for read-only or W for writeable: ");
|
|
|
|
ConsoleKeyInfo key = // ReadKey();
|
|
new ConsoleKeyInfo('R', ConsoleKey.R,
|
|
shift: false, alt: false, control: false);
|
|
|
|
WriteLine();
|
|
|
|
Stream s = null;
|
|
|
|
if (key.Key == ConsoleKey.R)
|
|
{
|
|
s = File.Open(
|
|
Path.Combine(path, "file.txt"),
|
|
FileMode.OpenOrCreate,
|
|
FileAccess.Read);
|
|
}
|
|
else
|
|
{
|
|
s = File.Open(
|
|
Path.Combine(path, "file.txt"),
|
|
FileMode.OpenOrCreate,
|
|
FileAccess.Write);
|
|
}
|
|
|
|
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);
|
|
|
|
#!markdown
|
|
|
|
## Simplifying switch statements with switch expressions
|
|
|
|
#!csharp
|
|
|
|
message = s switch
|
|
{
|
|
FileStream writeableFile when s.CanWrite
|
|
=> "The stream is a file that I can write to.",
|
|
FileStream readOnlyFile
|
|
=> "The stream is a read-only file.",
|
|
MemoryStream ms
|
|
=> "The stream is a memory address.",
|
|
null
|
|
=> "The stream is null.",
|
|
_
|
|
=> "The stream is some other type."
|
|
};
|
|
WriteLine(message);
|
|
|
|
#!markdown
|
|
|
|
# Understanding iteration statements
|
|
|
|
#!markdown
|
|
|
|
## Looping with the while statement
|
|
|
|
#!csharp
|
|
|
|
int x = 0;
|
|
|
|
while (x < 10)
|
|
{
|
|
WriteLine(x);
|
|
x++;
|
|
}
|
|
|
|
#!markdown
|
|
|
|
## Looping with the do statement
|
|
|
|
#!csharp
|
|
|
|
string password = string.Empty;
|
|
int attempts = 0;
|
|
|
|
do
|
|
{
|
|
if (attempts == 10)
|
|
{
|
|
break;
|
|
}
|
|
Write("Enter your password: ");
|
|
password = "Pa$$w0rd"; // ReadLine();
|
|
attempts++;
|
|
}
|
|
while (password != "Pa$$w0rd");
|
|
|
|
if (attempts == 10)
|
|
{
|
|
WriteLine("You failed after 10 attempts!");
|
|
}
|
|
else
|
|
{
|
|
WriteLine("Correct!");
|
|
}
|
|
|
|
#!markdown
|
|
|
|
## Looping with the for statement
|
|
|
|
#!csharp
|
|
|
|
for (int y = 1; y <= 10; y++)
|
|
{
|
|
WriteLine(y);
|
|
}
|
|
|
|
#!markdown
|
|
|
|
## Looping with the foreach statement
|
|
|
|
#!csharp
|
|
|
|
string[] names = { "Adam", "Barry", "Charlie" };
|
|
|
|
foreach (string name in names)
|
|
{
|
|
WriteLine($"{name} has {name.Length} characters.");
|
|
}
|
|
|
|
#!markdown
|
|
|
|
# Casting and converting between types
|
|
|
|
#!csharp
|
|
|
|
using static System.Console;
|
|
using static System.Convert;
|
|
|
|
#!markdown
|
|
|
|
## Casting numbers implicitly and explicitly
|
|
|
|
#!csharp
|
|
|
|
int a = 10;
|
|
double b = a; // an int can be safely cast into a double
|
|
WriteLine(b);
|
|
|
|
double c = 9.8;
|
|
int d = (int)c; // compiler gives an error for this line before adding (int)
|
|
WriteLine(d); // d is 9 losing the .8 part due to the (int) cast above
|
|
|
|
long e = 10;
|
|
int f = (int)e;
|
|
WriteLine($"e is {e:N0} and f is {f:N0}");
|
|
e = 5_000_000_000; // long.MaxValue;
|
|
f = (int)e;
|
|
WriteLine($"e is {e:N0} and f is {f:N0}");
|
|
|
|
#!markdown
|
|
|
|
## Converting with the System.Convert type
|
|
|
|
#!csharp
|
|
|
|
double g = 9.8;
|
|
int h = ToInt32(g); // a method of System.Convert
|
|
WriteLine($"g is {g} and h is {h}");
|
|
|
|
#!markdown
|
|
|
|
## Understanding the default rounding rules
|
|
|
|
#!csharp
|
|
|
|
double[] doubles = new[]
|
|
{ 9.49, 9.5, 9.51, 10.49, 10.5, 10.51 };
|
|
|
|
foreach (double n in doubles)
|
|
{
|
|
WriteLine($"ToInt32({n}) is {ToInt32(n)}");
|
|
}
|
|
|
|
#!markdown
|
|
|
|
## Taking control of rounding rules
|
|
|
|
#!csharp
|
|
|
|
foreach (double n in doubles)
|
|
{
|
|
WriteLine(format:
|
|
"Math.Round({0}, 0, MidpointRounding.AwayFromZero) is {1}",
|
|
arg0: n,
|
|
arg1: Math.Round(value: n, digits: 0,
|
|
mode: MidpointRounding.AwayFromZero));
|
|
}
|
|
|
|
#!markdown
|
|
|
|
## Converting from any type to a string
|
|
|
|
#!csharp
|
|
|
|
int number = 12;
|
|
WriteLine(number.ToString());
|
|
|
|
bool boolean = true;
|
|
WriteLine(boolean.ToString());
|
|
|
|
DateTime now = DateTime.Now;
|
|
WriteLine(now.ToString());
|
|
|
|
object me = new object();
|
|
WriteLine(me.ToString());
|
|
|
|
#!markdown
|
|
|
|
## Converting from a binary object to a string
|
|
|
|
#!csharp
|
|
|
|
// allocate array of 128 bytes
|
|
byte[] binaryObject = new byte[128];
|
|
|
|
// populate array with random bytes
|
|
(new Random()).NextBytes(binaryObject);
|
|
|
|
WriteLine("Binary Object as bytes:");
|
|
|
|
for(int index = 0; index < binaryObject.Length; index++)
|
|
{
|
|
Write($"{binaryObject[index]:X} ");
|
|
}
|
|
WriteLine();
|
|
|
|
// convert to Base64 string and output as text
|
|
string encoded = ToBase64String(binaryObject);
|
|
|
|
WriteLine($"Binary Object as Base64: {encoded}");
|
|
|
|
#!markdown
|
|
|
|
## Parsing from strings to numbers or dates and times
|
|
|
|
#!csharp
|
|
|
|
int age = int.Parse("27");
|
|
DateTime birthday = DateTime.Parse("4 July 1980");
|
|
|
|
WriteLine($"I was born {age} years ago.");
|
|
WriteLine($"My birthday is {birthday}.");
|
|
WriteLine($"My birthday is {birthday:D}.");
|
|
|
|
#!markdown
|
|
|
|
## Errors using Parse
|
|
|
|
#!csharp
|
|
|
|
int count = int.Parse("abc");
|
|
|
|
#!markdown
|
|
|
|
## Avoiding exceptions using the TryParse method
|
|
|
|
#!csharp
|
|
|
|
Write("How many eggs are there? ");
|
|
string input = "12"; // change to "twelve"
|
|
|
|
if (int.TryParse(input, out int count))
|
|
{
|
|
WriteLine($"There are {count} eggs.");
|
|
}
|
|
else
|
|
{
|
|
WriteLine("I could not parse the input.");
|
|
}
|
|
|
|
#!markdown
|
|
|
|
## Wrapping error-prone code in a try block
|
|
|
|
#!csharp
|
|
|
|
WriteLine("Before parsing");
|
|
Write("What is your age? ");
|
|
string input = "49";
|
|
|
|
try
|
|
{
|
|
int age = int.Parse(input);
|
|
WriteLine($"You are {age} years old.");
|
|
}
|
|
catch (OverflowException)
|
|
{
|
|
WriteLine("Your age is a valid number format but it is either too big or small.");
|
|
}
|
|
catch (FormatException)
|
|
{
|
|
WriteLine("The age you entered is not a valid number format.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
WriteLine($"{ex.GetType()} says {ex.Message}");
|
|
}
|
|
|
|
WriteLine("After parsing");
|
|
|
|
#!markdown
|
|
|
|
## Throwing overflow exceptions with the checked statement
|
|
|
|
#!csharp
|
|
|
|
try
|
|
{
|
|
checked
|
|
{
|
|
int x = int.MaxValue - 1;
|
|
WriteLine($"Initial value: {x}");
|
|
x++;
|
|
WriteLine($"After incrementing: {x}");
|
|
x++;
|
|
WriteLine($"After incrementing: {x}");
|
|
x++;
|
|
WriteLine($"After incrementing: {x}");
|
|
}
|
|
}
|
|
catch (OverflowException)
|
|
{
|
|
WriteLine("The code overflowed but I caught the exception.");
|
|
}
|
|
|
|
#!markdown
|
|
|
|
## Disabling compiler overflow checks with the unchecked statement
|
|
|
|
#!csharp
|
|
|
|
int y = int.MaxValue + 1;
|
|
|
|
#!csharp
|
|
|
|
unchecked
|
|
{
|
|
int y = int.MaxValue + 1;
|
|
WriteLine($"Initial value: {y}");
|
|
y--;
|
|
WriteLine($"After decrementing: {y}");
|
|
y--;
|
|
WriteLine($"After decrementing: {y}");
|
|
}
|