#!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("--------------------------------------------------------------------------");