cs11dotnet7/notebooks/Chapter03.dib
2022-02-09 10:30:33 +00:00

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}");
}