C# - Top 10 New Features (Part 4 Of 4)

Article Overview

  • Background
  • Pre-requisites
  • Null-Coalescing Assignment
    • Points
    • Example
  • Async Streams
    • Points
    • Example
  • Property, Tuple, and Positional Patterns
    • Points
    • Example
  • Summary

Background

 
I have divided this whole article into 4 parts to make it easy to understand. This article mainly focuses on three key features and enhancements to C# 8.0:
  • Null-Coalescing Assignment
  • Async Streams
  • Property, Tuple, and Positional Patterns
Here, I have kept all the implementation details with a complete example.
 
Prerequisites
For your reference, I have kept all the examples in a single .cs file and uploaded it with this article for easy to use.
 

Null-Coalescing Assignment

 
Below are the key syntax improvements:
  • New version introduces null-coalescing assignment operator ??=.
  • Use ??= operator to assign a value of its right-hand operand to its left-hand operand only if the left-hand operand evaluates to null.
  • It simplifies the common coding pattern where the variable is assigned the value if it is null.
Now, let us understand it by example.
 
Example 1
  1. int? i = 1; 

  2. int j = 2;  
  3. i ??= j; 

  4. Console.WriteLine($"{i}");    
Example 2
  1. int? variable = null

  2. int expression = 5; 

  3. if (variable == null)    
  4. {    
  5.   variable = expression; // C# 1..7    
  6. }    

  7. variable ??= expression; // C# 8  

  8. Console.WriteLine($"{variable}");   

Async Streams

  • For developing IoT applications this feature will be very useful where you are dealing with lots of asynchronous calls returning the data.
  • It allows using ‘async’ to iterate over the collections.
Now, let us understand by example.

Example
  1. await foreach (var number in GenerateSequence())  
  2. {  
  3.     Console.WriteLine(number);  


  4. public static async System.Collections.Generic.IAsyncEnumerable<int> GenerateSequence()  
  5. {  
  6.     for (int i = 0; i < 20; i++)  
  7.     {  
  8.         await System.Threading.Tasks.Task.Delay(100);  

  9.         yield return i;  
  10.     }  
  11. }  

Property, Tuple, and Positional Patterns

Property Patterns
  • Property pattern will enable you to match on properties of an object examined.
  • For example, for the eCommerce website, it must compute sales tax based on the buyer's address. Sales tax amount will depend on the State property of the address.
Now, let us understand by example.
 
Example 
  1. Address location = new Address();  
  2. location.State = "MN"

  3. decimal salePrice = 10;  
  4. Console.WriteLine(ComputeSalesTax(location, salePrice)); 

  5. public static decimal ComputeSalesTax(Address location, decimal salePrice) => location switch  
  6. {  
  7.     { State: "WA" } => salePrice * 0.06M,  
  8.     { State: "MN" } => salePrice * 0.75M,  
  9.     { State: "MI" } => salePrice * 0.05M,  
  10.     // other cases removed for brevity...  
  11.     _ => 0M  
  12. }; 

  13. public class Address  
  14. {  
  15.     public string State;  
  16. }  
Tuple Patterns
  • It allows matching of more than one value into a single pattern matching expression.
  • Some algorithms depend on multiple inputs.
  • Tuple patterns allow to switch based on the multiple values which are expressed as a tuple.
Example 
  1. Console.WriteLine(RockPaperScissors("rock""paper"));
  2.  
  3. public static string RockPaperScissors(string first, string second) => (first, second) switch  
  4. {  
  5.     ("rock""paper") => "rock is covered by paper. Paper wins.",  
  6.     ("rock""scissors") => "rock breaks scissors. Rock wins.",  
  7.     ("paper""rock") => "paper covers rock. Paper wins.",  
  8.     ("paper""scissors") => "paper is cut by scissors. Scissors wins.",  
  9.     ("scissors""rock") => "scissors is broken by rock. Rock wins.",  
  10.     ("scissors""paper") => "scissors cuts paper. Scissors wins.",  
  11.     (_, _) => "tie"  
  12. };   
Positional Patterns
  • It can be used while testing a type with a Deconstructor method.
  • Its syntax is very similar to tuple patterns. 
Example
  1. Point2 obj = new Point2(1, 5); 

  2. Console.WriteLine(GetQuadrant(obj));
  3.  
  4. static Quadrant GetQuadrant(Point2 point) => point switch  
  5. {  
  6.     (0, 0) => Quadrant.Origin,  
  7.     var (x, y) when x > 0 && y > 0 => Quadrant.One,  
  8.     var (x, y) when x < 0 && y > 0 => Quadrant.Two,  
  9.     var (x, y) when x < 0 && y < 0 => Quadrant.Three,  
  10.     var (x, y) when x > 0 && y < 0 => Quadrant.Four,  
  11.     var (_, _) => Quadrant.OnBorder,  
  12.     _ => Quadrant.Unknown  
  13. }; 

  14. public enum Quadrant  
  15. {  
  16.     Unknown,    Origin,    One,    Two,    Three,    Four,    OnBorder  


  17. public class Point2  
  18. {  
  19.     public int X { get; }  
  20.     public int Y { get; }  
  21.   
  22.     public Point2(int x, int y) => (X, Y) = (x, y);  
  23.   
  24.     public void Deconstruct(out int x, out int y) => (x, y) = (X, Y);  
  25. }  

Summary

 
Now, I believe you will be able to implement "Null-Coalescing Assignment", "Async Streams", and "Property, Tuple, and Positional Patterns" in C# 8.0.
 
Previous parts of this series,


Similar Articles