diff --git a/021_Casting_and_conversion_techniques/021_csharp.md b/021_Casting_and_conversion_techniques/021_csharp.md index 30fc68d..659b3d3 100644 --- a/021_Casting_and_conversion_techniques/021_csharp.md +++ b/021_Casting_and_conversion_techniques/021_csharp.md @@ -493,3 +493,360 @@ conversion `(int)myDecimal`) - Use the `Convert` class when you want to perform a narrowing conversion, but want to perform rounding, not a truncation of information + +--- + +## Exercise + +### Examine the TryParse() method + +When working with data, sometimes, you need to convert string data into a +numeric data type. As you learned in the previous unit, because the string data +type can hold a non-numeric value, it's possible that performing a conversion +from a `string` into a numeric data type causes a runtime error. + +For example, the following code: + +```cs +string name = "Bob"; +Console.WriteLine(int.Parse(name)); +``` + +Causes the following exception: + +```txt +System.FormatException: 'Input string was not in a correct format.' +``` + +To avoid a format exception, use the TryParse() method on the target data +type. + +### Use TryParse() + +The TryParse() method does several things simultaneously: + +- It attempts to parse a string into the given numeric data type. +- If successful, it stores the converted value in an out parameter, explained +in following section. +- It returns a `bool` to indicate whether the action succeeded or failed. + +You can use the Boolean return value to take action on the value (like +performing some calculation), or display a message if the parse operation was +unsuccessful. + +> Note +> In this exercise, you'll use the `int` data type, but a similar `TryParse()` +method is available on all numeric data types. + +#### Out parameters + +Methods can return a value or return "void" - meaning they return no value. +Methods can also return values through `out` parameters, which are defined just +like an input parameter, but include the `out` keyword. + +#### TryParse() a string into an int + +Delete or use the line comment operator `//` to comment out all of the code +from the previous exercises. + +Update your code in the editor as follows: + +```cs +string value = "102"; +int result = 0; +if (int.TryParse(value, out result)) { + Console.WriteLine($"Measurement: {result}"); +} else { + Console.WriteLine("Unable to report the measurement."); +} +``` + +Examine this line of code: + +```cs +if (int.TryParse(value, out result)) +``` + +When calling a method with an `out` parameter, you must use the keyword `out` +before the variable, which holds the value. The `out` parameter is assigned to +the `result` variable in the code `(int.TryParse(value, out result)`. You can +then use the value the `out` parameter contains throughout the rest of your +code using the variable `result`. + +The `int.TryParse()` method returns `true` if it successfully converted the +`string` variable `value` into an `int`; otherwise, it returns `false`. So, +surround the statement in an `if` statement, and then perform the decision +logic, accordingly. + +The converted value is stored in the `int` variable `result`. The `int` +variable `result` is declared and initialized before this line of code, so it +should be accessible both *inside* the code blocks that belong to the `if` and +`else` statements, as well as *outside* of them. + +The `out` keyword instructs the compiler that the `TryParse()` method doesn't +return a value the traditional way only (as a return value), but also +communicates an output through this two-way parameter. + +When you run the code, you should see the following output: + +```txt +Measurement: 102 +``` + +#### Use the parsed `int` later in code + +To demonstrate that the `result` variable that was declared earlier, is +populated by the `out` parameter and is also usable later in your code, update +your code as follows: + +```cs +string value = "102"; +int result = 0; +if (int.TryParse(value, out result)) { + Console.WriteLine($"Measurement: {result}"); +} else { + Console.WriteLine("Unable to report the measurement."); +} +Console.WriteLine($"Measurement (w/ offset): {50 + result}"); +``` + +You should see the following output: + +```txt +Measurement: 102 +Measurement (w/ offset): 152 +``` + +Examine the last line of code in the previous sample, +`Console.WriteLine($"Measurement (w/ offset): {50 + result}");`, Since the +`result` variable is defined outside of the if statement, it can be accessed +later in your code. + +#### Modify the string variable to a value that can't be parsed + +Lastly, look at the other scenario - where the `TryParse()` is intentionally +given a bad value that can't be converted into an int. + +#### Modify the first line of code, reinitialize the variable `value` to a different value. + +```cs +string value = "bad"; +``` + +Also, modify the last line of code to ensure that the result is greater than 0 +before showing the second message. + +```cs +if (result > 0) + Console.WriteLine($"Measurement (w/ offset): {50 + result}"); +The entire code example should now match the following code: +``` + +```cs +string value = "bad"; +int result = 0; +if (int.TryParse(value, out result)) { + Console.WriteLine($"Measurement: {result}"); +} else { + Console.WriteLine("Unable to report the measurement."); +} + +if (result > 0) + Console.WriteLine($"Measurement (w/ offset): {50 + result}"); +``` + +Save your code file, and then run your code. You should get the following +result: + +```txt +Unable to report the measurement. +``` + +Examine the last two lines of code added in the previous sample. + +```cs +if (result > 0) + Console.WriteLine($"Measurement (w/ offset): {50 + result}"); +``` + +Since `result` is defined outside of the `if` statement, `result` can be +accessed later in your code outside of the code blocks. So then `result` can be +checked for a value greater than zero before allowing `result` + offset to be +written as output. Checking for a `result` value greater than zero avoids +printing an offset value after the `Unable to report the measurement.` message. + +### Recap + +The `TryParse()` method is a valuable tool. Here are few quick ideas to remember. + +- Use `TryParse()` when converting a string into a numeric data type. +- `TryParse()` returns `true` if the conversion is successful, `false` if it's +unsuccessful. +- Out parameters provide a secondary means of a method returning a value. In +this case, the `out` parameter returns the converted value. +- Use the keyword `out` when passing in an argument to a method that has +defined an `out` parameter. + +--- + +## Exercise + +### Complete a challenge to combine string array values as strings and as integers + +Code challenges reinforce what you've learned and help you gain some confidence +before continuing. + +This module features two code challenges. This first challenge forces you to +split up the data depending on its type and either concatenate or add the data +accordingly. + +> Note +> The code samples in this exercise are designed based on en-US culture setting +s, and use a period (`.`) as the decimal separator. Building and running the +code with a culture setting that uses a different decimal separators (such as a +comma `,`) may give unexpected results or errors. To fix this issue, replace +the period decimal separators in the code samples with your local decimal +separator (such as `,`). Alternatively, to run a program using the en-US +culture setting, add the following code to the top of your program: +`using System.Globalization;` and after any other `using` statements add +`CultureInfo.CurrentCulture = new CultureInfo("en-US");`. + +Select and delete all code lines in the code editor. Optionally, use the line +comment operator `//` to comment out all of the code from the previous step. + +To instantiate a string array, enter the following "starter" code: + +```cs +string[] values = { "12.3", "45", "ABC", "11", "DEF" }; +``` + +Create a looping structure that can be used to iterate through each string +value in the array `values`. + +Complete the required code, placing it within the array looping structure code +block. It's necessary to implement the following business rules in your code +logic: + +- Rule 1: If the value is alphabetical, concatenate it to form a message. + +- Rule 2: If the value is numeric, add it to the total. + +- Rule 3: The result should match the following output: + +```txt +Message: ABCDEF +Total: 68.3 +``` + +The Program.cs file must be saved before building or running the code. + +At the Terminal command prompt, to run your code, type `dotnet run` and then +press Enter. + +You should see the following output: + +```txt + Message: ABCDEF + Total: 68.3 +``` + +> Note +> If you see a message saying "Couldn't find a project to run", ensure that the Terminal command prompt displays the expected TestProject folder location. For example: C:\Users\someuser\Desktop\csharpprojects\TestProject> + +Whether you get stuck and need to peek at the solution or you finish +successfully, continue to view a solution to this challenge. + +--- + +## Exercise + +### Complete a challenge to output math operations as specific number types + +Here's a second chance to use what you've learned about casting and conversion +to solve a coding challenge. + +The following challenge helps you to understand the implications of casting +values considering the impact of narrowing and widening conversions. + +Delete or comment out all of the code from the earlier exercise + +Enter the following "starter" code: + +```cs +int value1 = 11; +decimal value2 = 6.2m; +float value3 = 4.3f; + +// Your code here to set result1 +// Hint: You need to round the result to nearest integer (don't just truncate) +Console.WriteLine($"Divide value1 by value2, display the result as an int: {result1}"); + +// Your code here to set result2 +Console.WriteLine($"Divide value2 by value3, display the result as a decimal: {result2}"); + +// Your code here to set result3 +Console.WriteLine($"Divide value3 by value1, display the result as a float: {result3}"); +``` + +Replace the code comments in the starter code with your own code to solve the +challenge: + +- Solve for `result1`: Divide `value1` by `value2`, display the result as an +`int` +- Solve for `result2`: Divide `value2` by `value3`, display the result as a +`decimal` +- Solve for `result3`: Divide `value3` by `value1`, display the result as a +`float` + +Solve the challenge so that your output resembles: + +```txt +Divide value1 by value2, display the result as an int: 2 +Divide value2 by value3, display the result as a decimal: 1.4418604651162790697674418605 +Divide value3 by value1, display the result as a float: 0.3909091 +``` + +The Program.cs file must be saved before building or running the code. + +At the Terminal command prompt, to run your code, type `dotnet run` and then +press Enter. + +You should see the following output: + +```txt +Divide value1 by value2, display the result as an int: 2 +Divide value2 by value3, display the result as a decimal: 1.4418604651162790697674418605 +Divide value3 by value1, display the result as a float: 0.3909091 +``` + +--- + +## Summary + +Your goal was to use several different techniques to change the data type of a +given value. + +You used *implicit conversion*, relying on the C# compiler to perform *widening +conversions*. When the compiler was unable to perform an implicit conversion, +you used explicit conversions. You used the `ToString()` method to explicitly +convert a numeric data type into a `string`. + +When you needed to perform `narrowing conversions`, you used several different +techniques. You used the casting operator `()` when the conversion could be +made safely and were willing to accept truncation of values after the decimal. +And you used the `Convert()` method when you wanted to perform a conversion and +use common rounding rules when performing a narrowing conversion. + +Finally, you used the `TryParse()` methods when the conversion from a `string` +to a numeric data type could potentially result in a data type conversion +exception. + +Without this wealth of options, it would be difficult to work in a typed +programming language. Fortunately, this well executed system of types, +conversion, and casting can be harnessed to build error free applications. + +### Resources + +- [Casting and type conversions (C# programming guide)](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/casting-and-type-conversions) +- [Built-in types (C# reference)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/built-in-types) +- [Default values of C# types (C# reference)](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/default-values) diff --git a/021_Casting_and_conversion_techniques/test_app/Program.cs b/021_Casting_and_conversion_techniques/test_app/Program.cs index 9d6bcc0..9036c07 100644 --- a/021_Casting_and_conversion_techniques/test_app/Program.cs +++ b/021_Casting_and_conversion_techniques/test_app/Program.cs @@ -63,3 +63,61 @@ int value_2 = Convert.ToInt32(1.5m); // converting rounds up Console.WriteLine(value_2); Console.WriteLine(sep); + +// string name = "Bob"; +// Console.WriteLine(int.Parse(name)); + +Console.WriteLine(sep); + +string value_3 = "102"; +result_1 = 0; +if (int.TryParse(value_3, out result_1)) { + Console.WriteLine($"Measurement: {result_1}"); +} else { + Console.WriteLine($"Unable to report the measurement.({value_3} - {result_1})"); +} + +Console.WriteLine(sep); + +string[] values = { "12.3", "45", "ABC", "11", "DEF" }; +float total = 0.0F; +string msg = ""; +foreach (string value in values) { + float temp = 0; + if (float.TryParse(value, out temp)) { + total += temp; + } else { + msg += value; + } +} + +Console.WriteLine($"Message: {msg}"); +Console.WriteLine($"Total: {total}"); + +Console.WriteLine(sep); + +int value_01 = 11; +decimal value_02 = 6.2m; +float value_03 = 4.3f; + +// Your code here to set result_01 +// Hint: You need to round the result to nearest integer (don't just truncate) +int result_01 = Convert.ToInt32(value_01 / value_02); +Console.Write("Divide value_01 by value_02, display the result as an int: "); +Console.WriteLine($"{result_01}"); + +// Your code here to set result_02 +decimal result_02 = value_02 / (decimal)value_03; +Console.Write($"Divide value_02 by value_03, display the result as a decimal: "); +Console.WriteLine($"{result_02}"); + +// Your code here to set result_03 +float result_03 = value_03 / value_01; +Console.Write($"Divide value_03 by value_01, display the result as a float: "); +Console.WriteLine($"{result_03}"); + +string testo = "hola"; +decimal test = (decimal)testo; +Console.WriteLine(test); + +