Book Image

Improving your C# Skills

By : Ovais Mehboob Ahmed Khan, John Callaway, Clayton Hunt, Rod Stephens
Book Image

Improving your C# Skills

By: Ovais Mehboob Ahmed Khan, John Callaway, Clayton Hunt, Rod Stephens

Overview of this book

This Learning Path shows you how to create high performing applications and solve programming challenges using a wide range of C# features. You’ll begin by learning how to identify the bottlenecks in writing programs, highlight common performance pitfalls, and apply strategies to detect and resolve these issues early. You'll also study the importance of micro-services architecture for building fast applications and implementing resiliency and security in .NET Core. Then, you'll study the importance of defining and testing boundaries, abstracting away third-party code, and working with different types of test double, such as spies, mocks, and fakes. In addition to describing programming trade-offs, this Learning Path will also help you build a useful toolkit of techniques, including value caching, statistical analysis, and geometric algorithms. This Learning Path includes content from the following Packt products: • C# 7 and .NET Core 2.0 High Performance by Ovais Mehboob Ahmed Khan • Practical Test-Driven Development using C# 7 by John Callaway, Clayton Hunt • The Modern C# Challenge by Rod Stephens
Table of Contents (26 chapters)
Title Page
Copyright and Credits
About Packt
Contributors
Preface
8
What to Know Before Getting Started
17
Files and Directories
18
Advanced C# and .NET Features
Index

New features in C# 7.0


C# is the most popular language in the .NET ecosystem and was first introduced with the .NET Framework in 2002. The current stable version of C# is 7. The following chart shows how C# 7.0 has progressed and what versions were introduced in different years:

Here are some of the new features that were introduced with C# 7.0:

  • Tuples
  • Pattern matching
  • Reference returns
  • Exceptions as expressions
  • Local functions
  • Out variables Literals
  • Async Main

Tuples

Tuples solve the problem of returning more than one value from a method. Traditionally, we can use out variables that are reference variables, and the value is changed if they are modified from the calling method. However, without parameters, there are some limitations, such as that it cannot be used with async methods and is not recommended to be used with external services.

Tuples have the following characteristics:

  • They are value types.
  • They can be converted to other Tuples.
  • Tuple elements are public and mutable.

A Tuple is represented as System.Tuple<T>, where T could be any type. The following example shows how a Tuple can be used with the method and how the values can be invoked:

static void Main(string[] args) 
{ 
  var person = GetPerson(); 
  Console.WriteLine($"ID : {person.Item1}, 
  Name : {person.Item2}, DOB : {person.Item3}");       
} 
static (int, string, DateTime) GetPerson() 
{ 
  return (1, "Mark Thompson", new DateTime(1970, 8, 11)); 
}

As you may have noticed, items are dynamically named and the first item is named Item1, the second Item2, and so on. On the other hand, we can also name the items so that the calling party should know about the value, and this can be done by adding the parameter name for each parameter in the Tuple, which is shown as follows:

static void Main(string[] args) 
{ 
  var person = GetPerson(); 
  Console.WriteLine($"ID : {person.id}, Name : {person.name}, 
  DOB : {person.dob}");  
} 
static (int id, string name, DateTime dob) GetPerson() 
{ 
  return (1, "Mark Thompson", new DateTime(1970, 8, 11)); 
} 

Note

To learn more about Tuples, please check the following link:https://docs.microsoft.com/en-us/dotnet/csharp/tuples.

Patterns

Patterns matching is the process of performing syntactical testing of the value to verify whether it matches the certain model. There are three types of patterns:

  • Constant patterns.
  • Type patterns.
  • Var patterns.

Constant pattern

A constant pattern is a simple pattern that checks for the constant value. Consider the following example: if the Person object is null, it will return and exit the body method.

The Person class is as follows:

class Person 
{ 
  public int ID { set; get; } 
  public string Name { get; set; }

 

 

  public DateTime DOB { get; set; } 
} 

In the preceding code snippet, we have a Person class that contains three properties, namely ID, Name, and DOB (Date of Birth).

The following statement checks for the person object with a null constant value and returns it if the object is null:

if (person is null) return; 

Type pattern

The type pattern can be used with an object to verify whether it matches the type or suffices the expression based on the conditions specified. Suppose we need to check whether the PersonID is int; assign that ID to another variable, i, and use it in the program, otherwise return:

if (!(person.ID is int i)) return; 
 
Console.WriteLine($"Person ID is {i}"); 

We can also use multiple logical operators to evaluate more conditions, as follows:

if (!(person.ID is int i) && !(person.DOB>DateTime.Now.AddYears(-20))) return;   

The preceding statement checks whether the Person.ID is null or not and whether the person is older than 20.

Var pattern

The var pattern checks if the var is equal to some type. The following example shows how the var pattern can be used to check for the type and print the Type name:

if (person is var Person) Console.WriteLine($"It is a person object and type is {person.GetType()}"); 

Note

To learn more about patterns, you can refer to the following link: https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-7#pattern-matching.

Reference returns

Reference returns allow a method to return an object as a reference instead of its value. We can define the reference return value by adding a ref keyword before the type in the method signature and when returning the object from the method itself.

Here is the signature of the method that allows reference returns:

public ref Person GetPersonInformation(int ID); 
 
Following is the implementation of the GetPersonInformation method that uses the ref keyword while returning the person's object.  
 
Person _person; 
public ref Person GetPersonInformation(int ID) 
{ 
  _person = CallPersonHttpService(); 
  return ref _person; 
} 

Expression bodied member extended

Expression bodied members were introduced in C# 6.0 where the syntactical expression of the method can be written in a simpler way. In C# 7.0, we can use this feature with a constructor, a destructor, an exception, and so on.

The following example shows how the constructor and destructor syntactic expressions can be simplified using expression bodied members:

public class PersonManager 
{ 
  //Member Variable 
  Person _person; 
 
  //Constructor 
  PersonManager(Person person) => _person = person; 
 
  //Destructor 
  ~PersonManager() => _person = null; 
} 

 

 

 

With properties, we can also simplify the syntactic expression, and the following is a basic example of how this can be written:

private String _name; 
public String Name 
{ 
  get => _name; 
  set => _name = value; 
} 

We can also use an expression bodied syntactic expression with exceptions and simplify the expression, which is shown as follows:

private String _name; 
public String Name 
{ 
  get => _name; 
  set => _name = value ?? throw new ArgumentNullException(); 
} 

In the preceding example, if the value is null, a new ArgumentNullException will be thrown.

Creating Local Functions

Functions that are created within a function are known as Local Functions. These are mainly used when defining helper functions that have to be in the scope of the function itself. The following example shows how the factorial of the number can be obtained by writing a Local Function and calling it recursively:

static void Main(string[] args) 
{ 
  Console.WriteLine(ExecuteFactorial(4));          
} 
 
static long ExecuteFactorial(int n) 
{ 
  if (n < 0) throw new ArgumentException("Must be non negative", 
  nameof(n)); 
            
  else return CheckFactorial(n); 
 
  long CheckFactorial(int x) 
  {
    if (x == 0) return 1; 
    return x * CheckFactorial(x - 1); 
  } 
}

Out variables

With C# 7.0, we can write cleaner code when using out variables. As we know, to use out variables, we have to first declare them. With the new language enhancement, we can now just write out as a prefix and specify the name of the variable that we need that value to be assigned to.

To clarify this concept, we will first see the traditional approach, which is shown as follows:

public void GetPerson() 
{ 
  int year; 
  int month; 
  int day; 
  GetPersonDOB(out year, out month, out day); 
} 
 
public void GetPersonDOB(out int year, out int month, out int day ) 
{ 
  year = 1980; 
  month = 11; 
  day = 3; 
} 

And here with C# 7.0, we can simplify the preceding GetPerson method, which is shown as follows:

public void GetPerson() 
{ 
  GetPersonDOB(out int year, out int month, out int day); 
} 

Async Main

As we already know, in .NET Framework, the Main method is the main entry point from where the application/program is executed by the OS. For example, in ASP.NET Core, Program.cs is the main class where the Main method is defined, which creates a WebHost object, runs the Kestrel server, and loads up the HTTP pipeline as configured in the Startup class.

In the previous version of C#, the Main method had the following signatures:

public static void Main();
public static void Main(string[] args);
public static int Main();
public static int Main(string[] args);

In C# 7.0, we can use Async Main to perform asynchronous operations. The Async/Await feature was initially released in .NET Framework 4.5 in order to execute methods asynchronously. Today, many APIs provides Async/Await methods to perform asynchronous operations.

Here are some additional signatures of the Main method that have been added with C# 7.1:

public static Task Main();
public static Task Main(string[] args);
public static Task<int> Main();
public static Task<int> Main(string[] args);

Because of the preceding async signatures, we can now call async methods from the Main entry point itself and use await to perform an asynchronous operation. Here is a simple example of ASP.NET Core that calls the RunAsync method instead of Run:

public class Program
{
  public static async Task Main(string[] args)
  {
    await BuildWebHost(args).RunAsync();
  }
  public static IWebHost BuildWebHost(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
    .UseStartup<Startup>()
    .Build();
}

 

Async Main is a feature of C# 7.1, and to enable this feature in Visual Studio 2017, you can go to the project properties, click on the Advance button and set the Language version as C# latest minor version (latest), which is shown as follows: