mirror of
https://github.com/markjprice/cs11dotnet7.git
synced 2025-12-06 05:32:03 +01:00
437 lines
10 KiB
Plaintext
437 lines
10 KiB
Plaintext
|
|
#!csharp
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
# Chapter 2 - Speaking C#
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
using static System.Console;
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Showing the compiler version
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
// #error version
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Help for writing correct code
|
||
|
|
|
||
|
|
In a .NET Interactive notebook, you do not need to end the last statement with a semi-colon.
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
// with two compile errors
|
||
|
|
Console.Writeline("Hello World!")
|
||
|
|
|
||
|
|
// fixed
|
||
|
|
Console.WriteLine("Hello World!")
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Revealing the extent of the C# vocabulary
|
||
|
|
|
||
|
|
When running this code inside a .NET Interactive notebook, it lists all possible assemblies, including some used by the extension like `Microsoft.DotNet.Interactive`.
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
using System.Linq;
|
||
|
|
using System.Reflection;
|
||
|
|
|
||
|
|
// loop through the assemblies that this app references
|
||
|
|
foreach (var r in Assembly.GetEntryAssembly()
|
||
|
|
.GetReferencedAssemblies())
|
||
|
|
{
|
||
|
|
// load the assembly so we can read its details
|
||
|
|
var a = Assembly.Load(new AssemblyName(r.FullName));
|
||
|
|
|
||
|
|
// declare a variable to count the number of methods
|
||
|
|
int methodCount = 0;
|
||
|
|
// loop through all the types in the assembly
|
||
|
|
foreach (var t in a.DefinedTypes)
|
||
|
|
{
|
||
|
|
// add up the counts of methods
|
||
|
|
methodCount += t.GetMethods().Count();
|
||
|
|
}
|
||
|
|
|
||
|
|
// output the count of types and their methods
|
||
|
|
Console.WriteLine(
|
||
|
|
"{0:N0} types with {1:N0} methods in {2} assembly.",
|
||
|
|
arg0: a.DefinedTypes.Count(),
|
||
|
|
arg1: methodCount,
|
||
|
|
arg2: r.Name);
|
||
|
|
}
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Naming things and assigning values
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
// let the heightInMetres variable become equal to the value 1.88
|
||
|
|
double heightInMetres = 1.88;
|
||
|
|
Console.WriteLine($"The variable {nameof(heightInMetres)} has the value {heightInMetres}.");
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Storing text
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
char letter = 'A'; // assigning literal characters
|
||
|
|
char digit = '1';
|
||
|
|
char symbol = '$';
|
||
|
|
char userChoice = GetSomeKeystroke(); // assigning from a fictitious function
|
||
|
|
|
||
|
|
string firstName = "Bob"; // assigning literal strings
|
||
|
|
string lastName = "Smith";
|
||
|
|
string phoneNumber = "(215) 555-4256";
|
||
|
|
|
||
|
|
// assigning a string returned from a fictitious function
|
||
|
|
string address = GetAddressFromDatabase(id: 563);
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Understanding verbatim strings
|
||
|
|
|
||
|
|
In a .NET Interactive notebook, a brighter red color is used for escaped characters inside a string value to make them easier to see.
|
||
|
|
|
||
|
|
`\t` means tab. `\b` means backspace. `\s` does is not a valid escape character.
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
string fullNameWithTabSeparator = "Bob\tSmith";
|
||
|
|
|
||
|
|
string filePath = "C:\televisions\sony\bravia.txt";
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
string filePath = @"C:\televisions\sony\bravia.txt";
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Storing numbers
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
// unsigned integer means positive whole number or 0
|
||
|
|
uint naturalNumber = 23;
|
||
|
|
|
||
|
|
// integer means negative or positive whole number or 0
|
||
|
|
int integerNumber = -23;
|
||
|
|
|
||
|
|
// float means single-precision floating point
|
||
|
|
// F suffix makes it a float literal
|
||
|
|
float realNumber = 2.3F;
|
||
|
|
|
||
|
|
// double means double-precision floating point
|
||
|
|
double anotherRealNumber = 2.3; // double literal
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Storing whole numbers
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
// three variables that store the number 2 million
|
||
|
|
int decimalNotation = 2_000_000;
|
||
|
|
int binaryNotation = 0b_0001_1110_1000_0100_1000_0000;
|
||
|
|
int hexadecimalNotation = 0x_001E_8480;
|
||
|
|
|
||
|
|
// check the three variables have the same value
|
||
|
|
// both statements output true
|
||
|
|
Console.WriteLine($"{decimalNotation == binaryNotation}");
|
||
|
|
Console.WriteLine(
|
||
|
|
$"{decimalNotation == hexadecimalNotation}");
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Writing code to explore number sizes
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
Console.WriteLine($"int uses {sizeof(int)} bytes and can store numbers in the range {int.MinValue:N0} to {int.MaxValue:N0}.");
|
||
|
|
Console.WriteLine($"double uses {sizeof(double)} bytes and can store numbers in the range {double.MinValue:N0} to {double.MaxValue:N0}.");
|
||
|
|
Console.WriteLine($"decimal uses {sizeof(decimal)} bytes and can store numbers in the range {decimal.MinValue:N0} to {decimal.MaxValue:N0}.");
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Comparing double and decimal
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
Console.WriteLine("Using doubles:");
|
||
|
|
double a = 0.1;
|
||
|
|
double b = 0.2;
|
||
|
|
|
||
|
|
if (a + b == 0.3)
|
||
|
|
{
|
||
|
|
Console.WriteLine($"{a} + {b} equals 0.3");
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
Console.WriteLine($"{a} + {b} does NOT equal 0.3");
|
||
|
|
}
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
Console.WriteLine("Using decimals:");
|
||
|
|
decimal c = 0.1M; // M suffix means a decimal literal value
|
||
|
|
decimal d = 0.2M;
|
||
|
|
|
||
|
|
if (c + d == 0.3M)
|
||
|
|
{
|
||
|
|
Console.WriteLine($"{c} + {d} equals 0.3");
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
Console.WriteLine($"{c} + {d} does NOT equal 0.3");
|
||
|
|
}
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Storing Booleans
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
bool happy = true;
|
||
|
|
bool sad = false;
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Storing any type of object
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
object height = 1.88; // storing a double in an object
|
||
|
|
object name = "Amir"; // storing a string in an object
|
||
|
|
Console.WriteLine($"{name} is {height} metres tall.");
|
||
|
|
|
||
|
|
//int length1 = name.Length; // gives compile error!
|
||
|
|
int length2 = ((string)name).Length; // tell compiler it is a string
|
||
|
|
Console.WriteLine($"{name} has {length2} characters.");
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Storing dynamic types
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
// storing a string in a dynamic object
|
||
|
|
// string has a Length property
|
||
|
|
dynamic anotherName = "Ahmed";
|
||
|
|
|
||
|
|
// int does not have a Length property
|
||
|
|
anotherName = 12;
|
||
|
|
|
||
|
|
// an array of any type has a Length property
|
||
|
|
anotherName = new[] { 3, 5, 7 };
|
||
|
|
|
||
|
|
// this compiles but would throw an exception at run-time
|
||
|
|
// if you later store a data type that does not have a
|
||
|
|
// property named Length
|
||
|
|
Console.WriteLine($"Length is {anotherName.Length}");
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Specifying and inferring the type of a local variable
|
||
|
|
|
||
|
|
*Note*: click **Execute Code** in the following cell to import the namespaces for the subsequent code cell.
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
using System.IO;
|
||
|
|
using System.Xml;
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
var population = 66_000_000; // 66 million in UK
|
||
|
|
var weight = 1.88; // in kilograms
|
||
|
|
var price = 4.99M; // in pounds sterling
|
||
|
|
var fruit = "Apples"; // strings use double-quotes
|
||
|
|
var letter = 'Z'; // chars use single-quotes
|
||
|
|
var happy = true; // Booleans have value of true or false
|
||
|
|
|
||
|
|
// good use of var because it avoids the repeated type
|
||
|
|
// as shown in the more verbose second statement
|
||
|
|
var xml1 = new XmlDocument();
|
||
|
|
XmlDocument xml2 = new XmlDocument();
|
||
|
|
|
||
|
|
// bad use of var because we cannot tell the type, so we
|
||
|
|
// should use a specific type declaration as shown in
|
||
|
|
// the second statement
|
||
|
|
var file1 = File.CreateText(@"C:\something.txt");
|
||
|
|
StreamWriter file2 = File.CreateText(@"C:\something.txt");
|
||
|
|
|
||
|
|
XmlDocument xml3 = new(); // target-typed new in C# 9 or later
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
class Person
|
||
|
|
{
|
||
|
|
public DateTime BirthDate;
|
||
|
|
}
|
||
|
|
|
||
|
|
Person kim = new();
|
||
|
|
kim.BirthDate = new(1967, 12, 26); // instead of: new DateTime(1967, 12, 26)
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Getting default values for types
|
||
|
|
|
||
|
|
The default value of a `string` is `null` which outputs as nothing.
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
Console.WriteLine($"default(int) = {default(int)}");
|
||
|
|
Console.WriteLine($"default(bool) = {default(bool)}");
|
||
|
|
Console.WriteLine(
|
||
|
|
$"default(DateTime) = {default(DateTime)}");
|
||
|
|
Console.WriteLine(
|
||
|
|
$"default(string) = {default(string)}");
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
int number = 13;
|
||
|
|
Console.WriteLine($"number has been set to: {number}");
|
||
|
|
number = default;
|
||
|
|
Console.WriteLine($"number has been reset to its default: {number}");
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Storing multiple values an array
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
string[] names; // can reference any array of strings
|
||
|
|
|
||
|
|
// allocating memory for four strings in an array
|
||
|
|
names = new string[4];
|
||
|
|
|
||
|
|
// storing items at index positions
|
||
|
|
names[0] = "Kate";
|
||
|
|
names[1] = "Jack";
|
||
|
|
names[2] = "Rebecca";
|
||
|
|
names[3] = "Tom";
|
||
|
|
|
||
|
|
// looping through the names
|
||
|
|
for (int i = 0; i < names.Length; i++)
|
||
|
|
{
|
||
|
|
// output the item at index position i
|
||
|
|
Console.WriteLine(names[i]);
|
||
|
|
}
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Formatting using numbered positional arguments
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
using static System.Console;
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
int numberOfApples = 12;
|
||
|
|
decimal pricePerApple = 0.35M;
|
||
|
|
|
||
|
|
WriteLine(
|
||
|
|
format: "{0} apples costs {1:C}",
|
||
|
|
arg0: numberOfApples,
|
||
|
|
arg1: pricePerApple * numberOfApples);
|
||
|
|
|
||
|
|
string formatted = string.Format(
|
||
|
|
format: "{0} apples costs {1:C}",
|
||
|
|
arg0: numberOfApples,
|
||
|
|
arg1: pricePerApple * numberOfApples);
|
||
|
|
|
||
|
|
//WriteToFile(formatted); // writes the string into a file
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Formatting using interpolated strings
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
WriteLine($"{numberOfApples} apples costs {pricePerApple * numberOfApples:C}");
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Understanding format strings
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
string applesText = "Apples";
|
||
|
|
int applesCount = 1234;
|
||
|
|
|
||
|
|
string bananasText = "Bananas";
|
||
|
|
int bananasCount = 56789;
|
||
|
|
|
||
|
|
WriteLine(
|
||
|
|
format: "{0,-8} {1,6:N0}",
|
||
|
|
arg0: "Name",
|
||
|
|
arg1: "Count");
|
||
|
|
|
||
|
|
WriteLine(
|
||
|
|
format: "{0,-8} {1,6:N0}",
|
||
|
|
arg0: applesText,
|
||
|
|
arg1: applesCount);
|
||
|
|
|
||
|
|
WriteLine(
|
||
|
|
format: "{0,-8} {1,6:N0}",
|
||
|
|
arg0: bananasText,
|
||
|
|
arg1: bananasCount);
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Getting text input from the user
|
||
|
|
|
||
|
|
.NET Interactive notebooks do not support `ReadLine()` so in the following code we must set literal string values for the two variables.
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
Write("Type your first name and press ENTER: ");
|
||
|
|
string firstName = "Gary"; // cannot use Console.ReadLine()
|
||
|
|
|
||
|
|
Write("Type your age and press ENTER: ");
|
||
|
|
string age = "34"; // cannot use Console.ReadLine()
|
||
|
|
|
||
|
|
WriteLine(
|
||
|
|
$"Hello {firstName}, you look good for {age}.");
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Getting key input from the user
|
||
|
|
|
||
|
|
`Console.ReadKey()` does not work in a .NET notebook.
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Getting arguments
|
||
|
|
|
||
|
|
Arguments cannot be passed to a .NET notebook.
|
||
|
|
|
||
|
|
#!markdown
|
||
|
|
|
||
|
|
## Exercise 3 - Practice number sizes and ranges
|
||
|
|
|
||
|
|
#!csharp
|
||
|
|
|
||
|
|
WriteLine("--------------------------------------------------------------------------");
|
||
|
|
WriteLine("Type Byte(s) of memory Min Max");
|
||
|
|
WriteLine("--------------------------------------------------------------------------");
|
||
|
|
WriteLine($"sbyte {sizeof(sbyte),-4} {sbyte.MinValue,30} {sbyte.MaxValue,30}");
|
||
|
|
WriteLine($"byte {sizeof(byte),-4} {byte.MinValue,30} {byte.MaxValue,30}");
|
||
|
|
WriteLine($"short {sizeof(short),-4} {short.MinValue,30} {short.MaxValue,30}");
|
||
|
|
WriteLine($"ushort {sizeof(ushort),-4} {ushort.MinValue,30} {ushort.MaxValue,30}");
|
||
|
|
WriteLine($"int {sizeof(int),-4} {int.MinValue,30} {int.MaxValue,30}");
|
||
|
|
WriteLine($"uint {sizeof(uint),-4} {uint.MinValue,30} {uint.MaxValue,30}");
|
||
|
|
WriteLine($"long {sizeof(long),-4} {long.MinValue,30} {long.MaxValue,30}");
|
||
|
|
WriteLine($"ulong {sizeof(ulong),-4} {ulong.MinValue,30} {ulong.MaxValue,30}");
|
||
|
|
WriteLine($"float {sizeof(float),-4} {float.MinValue,30} {float.MaxValue,30}");
|
||
|
|
WriteLine($"double {sizeof(double),-4} {double.MinValue,30} {double.MaxValue,30}");
|
||
|
|
WriteLine($"decimal {sizeof(decimal),-4} {decimal.MinValue,30} {decimal.MaxValue,30}");
|
||
|
|
WriteLine("--------------------------------------------------------------------------");
|