Home Programming C# 7 and .NET: Designing Modern Cross-platform Applications

C# 7 and .NET: Designing Modern Cross-platform Applications

By Mark J. Price , Ovais Mehboob Ahmed Khan
books-svg-icon Book
Subscription $15.99 $10 p/m for three months
$10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
BUY NOW $10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
Subscription $15.99 $10 p/m for three months
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
  1. Free Chapter
    Controlling the Flow and Converting Types
About this book
C# is a widely used programming language, thanks to its easy learning curve, versatility, and support for modern paradigms. The language is used to create desktop apps, background services, web apps, and mobile apps. .NET Core is open source and compatible with Mac OS and Linux. There is no limit to what you can achieve with C# and .NET Core. This Learning Path begins with the basics of C# and object-oriented programming (OOP) and explores features of C#, such as tuples, pattern matching, and out variables. You will understand.NET Standard 2.0 class libraries and ASP.NET Core 2.0, and create professional websites, services, and applications. You will become familiar with mobile app development using Xamarin.Forms and learn to develop high-performing applications by writing optimized code with various profiling techniques. By the end of C# 7 and .NET: Designing Modern Cross-platform Applications, you will have all the knowledge required to build modern, cross-platform apps using C# and .NET. This Learning Path includes content from the following Packt products: • C# 7.1 and .NET Core 2.0 - Modern Cross-Platform Development - Third Edition by Mark J. Price • C# 7 and .NET Core 2.0 High Performance by Ovais Mehboob Ahmed Khan
Publication date:
December 2018
Publisher
Packt
ISBN
9781789956696

 

Chapter 1. Controlling the Flow and Converting Types

This chapter is about writing code that makes decisions, repeats blocks of statements, converts between types, handling exceptions, and checking for overflows in number variables.

This chapter covers the following sections:

  • Selection statements
  • Iteration statements
  • Casting and converting between types
  • Handling exceptions
  • Checking for overflow
 

Selection statements


Every application needs to be able to select from choices and branch along different code paths. The two selection statements in C# are if and switch. You can use if for all your code, but switch can simplify your code in some common scenarios.

Using Visual Studio 2017

Start Microsoft Visual Studio 2017. In Visual Studio, press Ctrl + Shift + N or choose File | New | Project....

In theNew Project dialog, in the Installed list, select Visual C#. In the list at the center, select Console App (.NET Core), type the name SelectionStatements, change the location to C:\Code, type the solution name Chapter03, and then click on OK.

Using Visual Studio Code on macOS, Linux, or Windows

If you have completed the previous chapters, then you will already have a Code folder in your user folder. If not, create it, and then create a subfolder named Chapter03, and then a sub-subfolder named SelectionStatements.

Start Visual Studio Code and open the /Chapter03/SelectionStatements/ folder.

In Visual Studio Code, navigate toView | Integrated Terminal, and then enter the following command:

dotnet new console

The if statement

The if statement determines which branch to follow by evaluating a Boolean expression. The else block is optional. The if statement can be nested and combined. Each Boolean expression can be independent of the others.

The code

Add the following statements inside the Main method to check whether this console application has any arguments passed to it:

if (args.Length == 0)
{
   WriteLine("There are no arguments.");
}
else
{
   WriteLine("There is at least one argument.");
}

As there is only a single statement inside each block, this code can be written without the curly braces, as shown in the following code:

if (args.Length == 0) 
  WriteLine("There are no arguments."); 
else 
  WriteLine("There is at least one argument."); 

This style of the if statement is not recommended because it can introduce serious bugs, for example, the infamous #gotofail bug in Apple's iPhone operating system. For 18 months after Apple's iOS 6 was released, it had a bug in its Secure Sockets Layer (SSL) encryption code, which meant that any user running Safari to connect to secure websites, such as their bank, were not properly secure because an important check was being accidentally skipped: https://gotofail.com/

Just because you can leave out the curly braces, doesn't mean you should. Your code is not "more efficient" without them, instead, it is less maintainable and potentially more dangerous, as this tweet points out:

Pattern matching with the if statement

A feature introduced with C# 7 is pattern matching. The if statement can use the is keyword in combination with declaring a local variable to make your code safer.

Add the following statements to the end of the Main method. If the value stored in the variable named o is an int, then the value is assigned to the local variable named i, which can then be used inside the if statement. This is safer than using the variable named o because we know for sure that i is an int variable and not something else:

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

Run the console application and view the output:

o is not an int so it cannot multiply!

Delete the double-quote characters around the "3" value so that the value stored in the variable named o is an int type instead of a string type and then rerun the console application and view the output:

3 x 4 = 12

The switch statement

The switch statement is different from the if statement because it compares a single expression against a list of multiple possible cases. Every case is related to the single expression. Every case must end with the break keyword (like case 1 in the following code) or the goto case keywords (like case 2 in the following code), or they should have no statements (like case 3 in the following code).

The code

Enter the following code after the if statements that you wrote previously. Note that the first line is a label that can be jumped to and the second line generates a random number. The switch statement branches based on the value of this random number:

A_label:
  var 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:
     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

Note

Good Practice You can use the goto keyword to jump to another case or a label. The goto keyword is frowned upon by most programmers but can be a good solution to code logic in some scenarios. Use it sparingly.

In Visual Studio 2017, run the program by pressing Ctrl + F5.

In Visual Studio Code, run the program by entering the following command into Integrated Terminal:

dotnet run

Run the program multiple times to see what happens in various cases of random numbers, as shown in the following output from Visual Studio Code:

bash-3.2$ dotnet run
My random number is 4
Three or four
One
bash-3.2$ dotnet run
My random number is 2
Two
One
bash-3.2$ dotnet run
My random number is 1
One

Pattern matching with the switch statement

Like the if statement, the switch statement supports pattern matching in C# 7. The case values no longer need to be literal values. They can be patterns.

Add the following statement to the top of the file:

using System.IO;

Add the following statements to the end of the Main method:

Note

If you are using macOS, then swap the commented statement that sets the path variable and replace my username with your user folder name.

// string path = "/Users/markjprice/Code/Chapter03";
// macOS
string path = @"C:\Code\Chapter03"; // Windows
    
Stream s = File.Open(
  Path.Combine(path, "file.txt"),
  FileMode.OpenOrCreate);
 
switch(s)
{
   case FileStream writeableFile when s.CanWrite:
     WriteLine("The stream is to a file that I can write to.");
     break;
   case FileStream readOnlyFile:
     WriteLine("The stream is to a read-only file.");
     break;
   case MemoryStream ms:
     WriteLine("The stream is to a memory address.");
     break;
   default: // always evaluated last despite its current position
     WriteLine("The stream is some other type.");
     break;
   case null:
     WriteLine("The stream is null.");
     break;
} 

Note that the variable named s is declared as a Stream type.

Note

You will learn more about the System.IO namespace and the Stream type in Chapter 7,Working with Files, Streams, and Serialization. You can read more about pattern matching at the following link:https://docs.microsoft.com/en-us/dotnet/csharp/pattern-matching

In .NET, there are multiple subtypes of Stream, including FileStream and MemoryStream. In C# 7 and later, your code can more concisely both branch, based on the subtype of stream, and declare and assign a local variable to safely use it.

Also, note that the case statements can include a when keyword to perform more specific pattern matching. In the first case statement in the preceding code, s would only be a match if the stream was FileStream and its CanWrite property was true.

 

Iteration statements


Iteration statements repeat a block either while a condition is true or for each item in a group. The choice of which statement to use is based on a combination of ease of understanding to solve the logic problem and personal preference.

Use either Visual Studio 2017 or Visual Studio Code to add a new console application project named IterationStatements.

In Visual Studio 2017, you can set the solution's start up project to be the current selection so that the current project runs when you press Ctrl + F5.

The while statement

The while statement evaluates a Boolean expression and continues to loop while it is true.

Type the following code inside the Main method:

int x = 0; 
while (x < 10) 
{ 
   WriteLine(x); 
   x++; 
} 

Run the console application and view the output:

0123456789

The do statement

The do statement is like while, except the Boolean expression is checked at the bottom of the block instead of the top, which means that it always executes at least once.

Type the following code at the end of the Main method and run it:

string password = string.Empty; 
do 
{ 
   Write("Enter your password: "); 
   password = ReadLine(); 
} while (password != "secret"); 
WriteLine("Correct!"); 

You will be prompted to enter your password repeatedly until you enter it correctly, as shown in the following output:

Enter your password: password
Enter your password: 12345678
Enter your password: ninja
Enter your password: asdfghjkl
Enter your password: secret
Correct!

As an optional exercise, add statements so that the user can only make ten attempts before an error message is displayed.

The for statement

The for statement is like while, except that it is more succinct. It combines an initializer statement that executes once at the start of the loop, a Boolean expression to check whether the loop should continue, and an incrementer that executes at the bottom of the loop. The for statement is commonly used with an integer counter, as shown in the following code:

for (int y = 1; y <= 10; y++)
{
   WriteLine(y);
}

Run the console application and view the output, which should be the numbers 1 to 10.

The foreach statement

The foreach statement is a bit different from the other three iteration statements. It is used to perform a block of statements on each item in a sequence, for example, an array or collection. Each item is read-only, and if the sequence is modified during iteration, for example, by adding or removing an item, then an exception will be thrown.

Type the following code inside the Main method, which creates an array of string variables and then outputs the length of each of them:

string[] names = { "Adam", "Barry", "Charlie" };
foreach (string name in names)
{
   WriteLine($"{name} has {name.Length} characters.");
}

Run the console application and view the output:

Adam has 4 characters.
Barry has 5 characters.
Charlie has 7 characters.

Technically, the foreach statement will work on any type that implements an interface called IEnumerable. An interface is a contract and you will learn more about them in Chapter 4,Implementing Interfaces and Inheriting Classes.

The compiler turns the foreach statement in the preceding code into something like this:

IEnumerator e = names.GetEnumerator();
while (e.MoveNext())
{ 
   string name = (string)e.Current; // Current is read-only!
   WriteLine($"{name} has {name.Length} characters.");
}

Note

Due to the use of an iterator, the variable declared in a foreach statement cannot be used to modify the value of the current item.

 

Casting and converting between types


You will often need to convert between different types. For example, data input is often done into a text field, so it is initially stored in a variable of the stringtype, but it then needs to be converted into a date, or time, or number, or some other data type, depending on how it should be stored and processed.

Casting has two varieties: implicit and explicit. Implicit casting happens automatically and it is safe, meaning that you will not lose any information. Explicit casting must be performed manually because it may lose information, for example, the accuracy of a number. By explicitly casting, you are telling the C# compiler that you understand and accept the risk.

Add a new console application project named CastingConverting.

Casting from numbers to numbers

Implicitly casting an int variable into a double variable is safe.

Casting numbers implicitly

In the Main method, enter the following statements:

int a = 10;
double b = a; // an int can be stored in a double
WriteLine(b);

You cannot implicitly cast a double variable into an int variable because it is potentially unsafe and would lose data.

In the Main method, enter the following statements:

double c = 9.8;
int d = c; // compiler gives an error for this line
WriteLine(d);

In Visual Studio 2017, press Ctrl + W, E to view the Error List, as shown in the following screenshot:

In Visual Studio Code, either view the PROBLEMS window, or enter the dotnet runcommand, which will give the following output:

Compiling Ch03_CastingConverting for .NETCoreApp,Version=v1.1
/usr/local/share/dotnet/dotnet compile-csc
@/Users/markjprice/Code/Chapter03/Ch03_CastingConverting/obj/
Debug/netcoreapp1.1/dotnet-compile.rsp returned Exit Code 1
/Users/markjprice/Code/Chapter03/Ch03_CastingConverting/Program.cs(14
,21): error CS0266: Cannot implicitly convert type 'double' to 'int'.
An explicit conversion exists (are you missing a cast?)
    
Compilation failed.
    0 Warning(s)
    1 Error(s)
    
Time elapsed 00:00:01.0461813

Casting numbers explicitly

You must explicitly cast a double variable into an int variable using a pair of round brackets around the type you want to cast the double type into. The pair of round brackets is the cast operator. Even then, you must beware that the part after the decimal point will be trimmed off without warning.

Modify the assignment statement for the dvariable, as shown in the following code:

double c = 9.8;
int d = (int)c;
WriteLine(d); // d is 9 losing the .8 part

Run the console application and view the output:

10
9

We must perform a similar operation when moving values between larger integers and smaller integers. Again, beware that you might lose information because any value too big will get set to -1!

Enter the following code:

long e = 10;
int f = (int)e;
WriteLine($"e is {e} and f is {f}");
e = long.MaxValue;
f = (int)e;
WriteLine($"e is {e} and f is {f}");

Run the console application and view the output:

e is 10 and f is 10
e is 9223372036854775807 and f is -1

Using the convert type

An alternative to using the casting operator is to use the System.Convert type.

At the top of the Program.cs file, type the following code:

using static System.Convert;

Add the following statements to the bottom of the Main method:

double g = 9.8; 
int h = ToInt32(g); 
WriteLine($"g is {g} and h is {h}"); 

Run the console application and view the output:

g is 9.8 and h is 10

Note

One difference between casting and converting is that converting rounds the double value up to 10 instead of trimming the part after the decimal point.

The System.Convert type can convert to and from all the C# number types as well as Booleans, strings, and date and time values.

Rounding numbers

You have now seen that the cast operator trims the decimal part of a real number and that the convert methods round up or down. However, what is the rule for rounding?

In British primary schools, children are taught to round up if the decimal part is .5 or higher and round down if the decimal part is less.

Enter the following code:

double i = 9.49;
double j = 9.5;
double k = 10.49;
double l = 10.5;
WriteLine($"i is {i}, ToInt(i) is {ToInt32(i)}");
WriteLine($"j is {j}, ToInt(j) is {ToInt32(j)}");
WriteLine($"k is {k}, ToInt(k) is {ToInt32(k)}");
WriteLine($"l is {l}, ToInt(l) is {ToInt32(l)}");

Run the console application and view the output:

i is 9.49, ToInt(i) is 9
j is 9.5, ToInt(j) is 10
k is 10.49, ToInt(k) is 10
l is 10.5, ToInt(l) is 10

Note that the rule for rounding in C# is subtly different. It will round up if the decimal part is .5 or higher and the nondecimal part is odd, but it will round down if the nondecimal part is even. It always rounds down if the decimal part is less than .5.

This rule is known as Banker's Rounding, and it is preferred because it reduces bias. Sadly, other languages such as JavaScript use the primary school rule.

Note

Good Practice For every programming language that you use, check its rounding rules. They may not work the way you expect!

Converting from any type to a string

The most common conversion is from any type into a string variable, so all types have a method named ToString that they inherit from the System.Object class.

The ToString method converts the current value of any variable into a textual representation. Some types can't be sensibly represented as text so they return their namespace and type name.

Add the following statements to the bottom of the Main method:

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());

Run the console application and view the output:

12
True
27/01/2017 13:48:54
System.Object

Converting from a binary object to a string

When you have a binary object that you want to store or transmit, it is best not to send the raw bits, because you never know how those bits could be misinterpreted, for example, by the network protocol transmitting them or another operating system that is reading the store binary object.

The safest thing to do is to convert the binary object into a string of safe characters. Programmers call this Base64 encoding.

The Convert type has a pair of methods, ToBase64String and FromBase64String, that perform this conversion for you.

Add the following statements to the end of the Main method:

// 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
string encoded = Convert.ToBase64String(binaryObject);

WriteLine($"Binary Object as Base64: {encoded}");

Note

By default, an int value would output assuming decimal notation, that is, base10. You can use format codes such as index:X to format the value using hexadecimal notation.

Run the console application and view the output:

Binary Object as bytes:
B3 4D 55 DE 2D E BB CF BE 4D E6 53 C3 C2 9B 67 3 45 F9 E5 20 61 7E 4F 7A 81 EC 49 F0 49 1D 8E D4 F7 DB 54 AF A0 81 5 B8 BE CE F8 36 90 7A D4 36 42 4 75 81 1B AB 51 CE 5 63 AC 22 72 DE 74 2F 57 7F CB E7 47 B7 62 C3 F4 2D 61 93 85 18 EA 6 17 12 AE 44 A8 D B8 4C 89 85 A9 3C D5 E2 46 E0 59 C9 DF 10 AF ED EF 8AA1 B1 8D EE 4A BE 48 EC 79 A5 A 5F 2F 30 87 4A C7 7F 5D C1 D 26 EE
Binary Object as Base64: s01V3i0Ou8++TeZTw8KbZwNF+eUgYX5PeoHsSfBJHY7U99tUr6CBBbi+zvg2kHrUNkIEdYEbq1HOBWOsInLedC9Xf8vnR7diw/QtYZOFGOoGFxKuRKgNuEyJhak81eJG4FnJ3xCv7e+KobGN7kq+SOx5pQpfLzCHSsd/XcENJu4=

Parsing from strings to numbers or dates and times

The second most common conversion is from strings to numbers or date and time values. The opposite of ToString is Parse. Only a few types have a Parse method, including all the number types and DateTime.

Add the following statements to the Main method:

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

Run the console application and view the output:

I was born 27 years ago.
My birthday is 04/07/1980 00:00:00.
My birthday is 04 July 1980.

Note

By default, a date and time value outputs with the short date and time format. You can use format codes such as D to output only the date part using long date format. There are many other format codes for common scenarios.

One problem with the Parse method is that it gives errors if the string cannot be converted.

Add the following statements to the bottom of the Main method:

int count = int.Parse("abc"); 

Run the console application and view the output:

Unhandled Exception: System.FormatException: Input string was not in
a correct format.

To avoid errors, you can use the TryParse method instead. TryParse attempts to convert the input string and returns true if it can convert it and false if it cannot. The out keyword is required to allow the TryParse method to set the count variable when the conversion works.

Replace the int count declaration with the following statements:

Write("How many eggs are there? ");
int count;
string input = Console.ReadLine();
if (int.TryParse(input, out count))
{
   WriteLine($"There are {count} eggs.");
}
else
{
   WriteLine("I could not parse the input.");
}

Run the application twice. The first time, enter 12. You will see the following output:

How many eggs are there? 12
There are 12 eggs.

The second time, enter twelve. You will see the following output:

How many eggs are there? twelve
I could not parse the count.

Note

You can also use the Convert type; however, like the Parse method, it gives an error if it cannot convert.

 

Handling exceptions when converting types


You've seen several scenarios when errors have occurred when converting types. C# calls this, an exception has been thrown.

Good practice is to avoid writing code that will throw an exception whenever possible, perhaps by performing if statement checks, but sometimes you can't. In those scenarios, you must catch the exception and handle it.

As you have seen, the default behavior of a console application is to display details about the exception in the output and then stop running the application.

You can take control over how to handle exceptions using the try statement.

The try statement

Add a new console application project named HandlingExceptions.

When you know that a statement can cause an error, you should wrap that statement in a try block. For example, parsing from a string to a number can cause an error. We do not have to do anything inside the catch block. When the following code executes, the error will get caught and will not be displayed, and the console application will continue running.

In the Main method, add the following statements:

WriteLine("Before parsing");
Write("What is your age? ");
string input = Console.ReadLine();
try
{
   int age = int.Parse(input);
   WriteLine($"You are {age} years old.");
}
catch
{
 
}
WriteLine("After parsing");

Run the console application and enter a valid age, for example, 43:

Before parsing
What is your age? 43
You are 43 years old.
After parsing

Run the console application again and enter an invalid age, for example, kermit;

Before parsing
What is your age? kermit
After parsing

The exception was caught, but it might be useful to see the type of error that occurred.

Catching all exceptions

Modify the catch statement to look like this:

catch(Exception ex)
{  
   WriteLine($"{ex.GetType()} says {ex.Message}");
} 

Run the console application and again enter an invalid age, for example, kermit:

Before parsing
What is your age? kermit
System.FormatException says Input string was not in a correct format.
After parsing

Catching specific exceptions

Now that we know which specific type of exception occurred, we can improve our code by catching just that type of exception and customizing the message that we display to the user.

Leave the existing catch block, but add the following code above it:

catch (FormatException)
{
   WriteLine("The age you entered is not a valid number format.");
} 
catch (Exception ex) 
{ 
   WriteLine($"{ex.GetType()} says {ex.Message}"); 
} 

Run the program and again enter an invalid age, for example, kermit:

Before parsing
What is your age? kermit
The age you entered is not a valid number format.
After parsing

The reason we want to leave the more general catch below is that there might be other types of exceptions that can occur. For example, run the program and enter a number that is too big for an integer, for example, 9876543210:

Before parsing
What is your age? 9876543210
System.OverflowException says Value was either too large or too small  for an 
Int32.
After parsing

Let's add another catch for this new type of exception:

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

Rerun the program one more time and enter a number that is too big:

Before parsing
What is your age? 9876543210
Your age is a valid number format but it is either too big or small.
After parsing

Note

The order in which you catch exceptions is important. The correct order is related to the inheritance hierarchy of the exception types. You will learn about inheritance in Chapter 3, Building Your Own Types with Object-Oriented Programming. However, don't worry too much about this—the compiler will give you build errors if you get exceptions in the wrong order anyway.

 

Checking for overflow


Earlier, we saw that when casting between number types, it was possible to lose information, for example, when casting from a long variable to an int variable. If the value stored in a type is too big, it will overflow.

Add a new console application project named CheckingForOverflow.

The checked statement

The checked statement tells .NET to throw an exception when an overflow happens instead of allowing it to happen silently.

We set the initial value of an int variable to its maximum value minus one. Then, we increment it several times, outputting its value each time. Note that once it gets above its maximum value, it overflows to its minimum value and continues incrementing from there.

Type the following code in the Main method and run the program:

int x = int.MaxValue - 1; 
WriteLine(x);
x++; 
WriteLine(x);
x++;
WriteLine(x);
x++;
WriteLine(x);

Run the console application and view the output:

2147483646
2147483647
-2147483648
-2147483647

Now, let's get the compiler to warn us about the overflow using the checked statement:

checked
{ 
   int x = int.MaxValue - 1; 
   WriteLine(x); 
   x++; 
   WriteLine(x); 
   x++; 
   WriteLine(x); 
   x++; 
   WriteLine(x); 
}

Run the console application and view the output:

2147483646
2147483647
Unhandled Exception: System.OverflowException: Arithmetic operation
resulted in an overflow.

Just like any other exception, we should wrap these statements in a try block and display a nicer error message for the user:

try
{
   // previous code goes here
}
catch(OverflowException)
{
   WriteLine("The code overflowed but I caught the exception.");
}

Run the console application and view the output:

2147483646
2147483647
The code overflowed but I caught the exception.

The unchecked statement

A related keyword is unchecked. This keyword switches off overflow checks within a block of code.

Type the following statement at the end of the previous statements. The compiler will not compile this statement because it knows it would overflow:

int y = int.MaxValue + 1; 

Press F6 or enter the dotnet runcommandto build and notice the error, as shown in the following screenshot from Visual Studio 2017:

Note that this is a compile-time check. To disable compile-time checks, we can wrap the statement in an unchecked block, as shown in the following code:

unchecked
{ 
   int y = int.MaxValue + 1; 
   WriteLine(y); // this will output -2147483648  
   y--;  
   WriteLine(y); // this will output 2147483647  
   y--;  
   WriteLine(y); // this will output 2147483646 
} 

Run the console application and view the output:

2147483646
2147483647
The code overflowed but I caught the exception.
-2147483648
2147483647
2147483646

Of course, it would be rare that you would want to explicitly switch off a check like this because it allows an overflow to occur. But, perhaps, you can think of a scenario where you might want that behavior.

 

Looking for help


This section is about how to find quality information about programming on the web.

Microsoft Docs and MSDN

The definitive resource for getting help with Microsoft developer tools and platforms used to be Microsoft Developer Network (MSDN). Now, it is Microsoft Docs: https://docs.microsoft.com/

Visual Studio 2017 is integrated with MSDN and Docs, so if you press F1 inside a C# keyword or type, then it will open your browser and take you to the official documentation.

Note

In Visual Studio Code, pressing F1 shows the Command Palette. It does not support context-sensitive help.

Go to definition

Another useful keystroke in both Visual Studio 2017 and Visual Studio Code is F12. This will show what the public definition of the type looks like by reading the metadata in the compiled assembly. Some tools will even reverse-engineer from the metadata and IL code back into C# for you.

Enter the following code, click inside int, and then press F12 (or right-click and choose Go To Definition):

int z;

In the new code window that appears, you can see that int is in the mscorlib.dll assembly; it is named Int32; it is in the System namespace; and int is therefore an alias for System.Int32, as shown in the following screenshot:

>

Microsoft defined int using a struct keyword, meaning that int is a value type stored on the stack. You can also see that int implements interfaces such as IComparable and has constants for its maximum and minimum values.

In the code editor window, scroll down to find the Parse methods and in Visual Studio 2017, you will need to click on the small box with a plus symbol in them to expand the code like I have done in the following screenshot:

In the comment, you will see that Microsoft has documented what exceptions might occur if you call this method (ArgumentNullException, FormatException, and OverflowException).

Now, we know that we need to wrap a call to this method in a try statement and which exceptions to catch.

Stack Overflow

Stack Overflow is the most popular third-party website for getting answers to difficult programming questions. It is so popular that search engines such as DuckDuckGo have a special way to write a query to search the site.

Go to >DuckDuckGo.com and enter the following query:

!so securestring

 

You will get the following results:

Google

You can search Google with advanced search options to increase the likelihood of finding what you need.

For example, if you are searching for information about garbage collection using a simple Google query, you will see a Wikipedia definition of garbage collection in computer science, and then a list of garbage collection services in your local area, as shown in the following screenshot:

We can improve the search by restricting it to a useful site such as Stack Overflow, as shown in the following screenshot:

We can improve the search even more by removing languages that we might not care about such as C++, as shown in the following screenshot:

Subscribing to blogs

To keep up to date with .NET, an excellent blog to subscribe to is the official .NET Blog written by the .NET engineering teams.  (https://blogs.msdn.microsoft.com/dotnet/).

Design patterns

A design pattern is a general solution to a common problem. Programmers have been solving the same problems over and over. When the community discovers a good reusable solution, we call it a design pattern. Many design patterns have been documented over the years.

Navigate to the following link to read about common design patterns:

https://en.wikipedia.org/wiki/Software_design_pattern#Classification_and_list

Microsoft has a group called patterns & practices that specializes in documenting and promoting design patterns for Microsoft products.

Note

Good Practice Before writing new code, search to see if someone else has already solved the problem in a general way.

Singleton pattern

One of the most common patterns is the Singleton pattern. Examples of Singleton in .NET are the Console and Math types.

Note

Read more about the Singleton pattern at: https://en.wikipedia.org/wiki/Singleton_pattern

 

Summary


In this chapter, you learned how to branch and loop, how to convert between types, how to catch exceptions, and most importantly, how to find help.

You are now ready to learn how to track down bugs in your code and squash them!

About the Authors
  • Mark J. Price

    Mark J. Price is a Microsoft Specialist: Programming in C# and Architecting Microsoft Azure Solutions, with over 20 years' experience. Since 1993, he has passed more than 80 Microsoft programming exams and specializes in preparing others to pass them. Between 2001 and 2003, Mark was employed to write official courseware for Microsoft in Redmond, USA. His team wrote the first training courses for C# while it was still an early alpha version. While with Microsoft, he taught "train-the-trainer" classes to get other MCTs up-to-speed on C# and .NET. Mark holds a Computer Science BSc. Hons. Degree.

    Browse publications by this author
  • Ovais Mehboob Ahmed Khan

    Ovais Mehboob Ahmed Khan is a seasoned programmer and solution architect with nearly 20 years of experience in software development, consultancy, and solution architecture. He has worked with various clients across the world and is currently working as a senior customer engineer at Microsoft. He specializes mainly in application development using .NET and OSS technologies, Microsoft Azure, and DevOps. He is a prolific writer who has written several books and articles on various technologies. He really enjoys talking about technology and has given a number of technical sessions around the world.

    Browse publications by this author
C# 7 and .NET: Designing Modern Cross-platform Applications
Unlock this book and the full library FREE for 7 days
Start now