Book Image

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

By : Mark J. Price, Ovais Mehboob Ahmed Khan
Book Image

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

By: Mark J. Price, Ovais Mehboob Ahmed Khan

Overview of 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
Table of Contents (25 chapters)
Title Page
Copyright
About Packt
Contributors
Preface
16
Designing Guidelines for .NET Core Application Performance
Index

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.