C# 8 Features

In this article, you will find some of the new C# 8 features described with pros and cons.

C# 8 is moving aggressively into the innovation world. Because of this strategy, Microsoft left many developers in a confused state. Currently, the developers have a very controversial opinion on the C# 8 new features. In this article, you can have a brief overview of the new proposed features of C# 8 language. I will describe the important features separately and demonstrate them with an example; the other less important features I will handle briefly. I will also write about the pros and cons of each important upcoming feature. Furthermore, I will give a rating score for each feature between 1 (Bad) and 10 (Excellent) and finally, I hope after reading this article, you will have a clear vision of the C# 8 Features.

The rating score is based on the below-listed criteria,
  • The technology behind: It is based on a proven and reliable technology or not?
  • Innovation: Did Microsoft do any innovation in the proposed feature?
  • My personal opinion: Based on my discussions with the communities and my expertise.

Default Interface Methods

Allows you to add new functionality to the interfaces of your libraries and ensure the backward compatibility with code written for older versions of those interfaces.
  1. interface IWriteLine  
  2. {  
  3.  public void WriteLine()  
  4.  {  
  5.  Console.WriteLine("Wow C# 8!");  
  6.  }  
  7. }  
Status: Prototype 
You can add new functionality to the interface without breaking the compatibility with the older versions of those interfaces.
It should be used carefully. Otherwise, it can easily lead to violating the single responsibility principles.
It is a very arguable feature, and it left many open discussions among the .NET community. I have handled this theme in depth in Reddit:
There is nothing new here. This concept is already applied in many languages and cloned from Java.
Technique behind
It is based on traits technique, and traits is a proven, powerful technique in OOP.
For more information about traits proof theory:
My personal opinion
I give this feature score 3. My tip you should think before using it and ask yourself, is there any other elegant solution, which might fit better to solve your problem?
For more detailed information about this feature, you can read my article.

Nullable reference type

Emits a compiler warning or error if a variable that must not be null is assigned to null.
  1. string? nullableString = null;  
  2. Console.WriteLine(nullableString.Length); // WARNING: may be null! Take care!  
Status: Preview 
It helps you to eliminate the NullReferenceException (The Billion Dollar Mistake, ALGOL60, Tony). Moreover, it helps you to solve the problems in code like a pyramid of doom.
However, in complex scenarios this feature may bring some confusion in regards to reference types and using “?” character for more information, please read https://codeblog.jonskeet.uk/2019/02/10/nullableattribute-and-c-8/.
In general, this feature is well accepted among the .NET Community.
Good innovation from Microsoft.
Technique behind
A proven technology.
My personal opinion
I give this feature 9. Yes, please use it! And, get rid of the NullReferenceException!
More Info

Advanced Pattern Matching

Provides the ability to deconstruct matched objects, giving you access to parts of their data structures. C# offers a rich set of patterns that can be used for matching.
  1. var point = new 3DPoint(1, 2, 3); //x=1, y=2, z=3  
  2. if (point is 3DPoint(1, var myY, _))  
  3. {  
  4.   // Code here will be executed only if the point .X == 1, myY is a new variable  
  5.   // that can be used in this scope.  
  6. }  
Status: Preview
Recursive pattern matching helps you decompose and navigate data structures in a very convenient, compact syntax. While pattern matching is conceptually similar to a sequence of (if, then) statements, so it will help you to write the code in a functional style.
In complex expressions, the syntax might be tricky and difficult to understand.
Well accepted in the .NET Community.
There is nothing new here.
Technique behind
This is a proven and known technology, which has been used for many years especially in functional programming.
My personal opinion
I give this feature 9. I expected pattern matching in C# will be trendy like LINQ and Lambda expressions. This feature can be very good combined with Records to make C# syntax more functional, but I am not sure that the Records will be released in the next C# 8 version or not.
More Info,

Async streams

Allows using ‘async’ to iterate over collections.
  1. await foreach (var x in enumerable)  
  2. {  
  3.   Console.WriteLine(x);  
  4. }  
Status: Preview
Async Streams provide an excellent way to represent asynchronous data sources that can be controlled by the consumer. For example, when downloading data from the web, we would like to create an asynchronous collection that returns the data in chunks as they become available.
Well accepted.
There is nothing new here! This technique is already used in many other languages Akka Streams.
Technique behind
Async Pull Programming Model is known and used for years.
My personal opinion
I give this feature 7. Please use it with the correct use cases like, downloading data from the web in chunks or getting a big query result in chunks from the database.
More Info,


Ranges are a very powerful construct when it comes to accessing sequences of data or getting a slice from a collection. This feature consisting of two parts,
Part I Index
Which can be used to obtain the collection from the beginning or from the end.
  1. Index i1 = 3; // number 3 from beginning  
  2. Index i2 = ^4; // number 4 from end  
  3. int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };  
  4. Console.WriteLine($"{a[i1]}, {a[i2]}"); // "3, 6"  
Part II Range
Access a sub-collection(slice) from a collection.
  1. var slice = a[i1..i2]; // { 3, 4, 5 }  
Status: Preview 
Nice syntax to access sequence of data from a collection.
And again, nothing is new here. A lot of similar technology is already used in other languages like Python.
Widely accepted.
My personal opinion
I give this feature an 8. It can make the code more readable and understandable.
More Info,

Caller Expression Attribute

Allows the caller to 'stringify' the expressions passed in at a call site. The constructor of the attribute will take a string argument specifying the name of the argument to stringify.
  1. public static class Verify {  
  2.     public static void InRange(int argument, int low, int high,  
  3.         [CallerArgumentExpression("argument")] string argumentExpression = null,  
  4.         [CallerArgumentExpression("low")] string lowExpression = null,  
  5.         [CallerArgumentExpression("high")] string highExpression = null) {  
  6.         if (argument < low) {  
  7.             throw new ArgumentOutOfRangeException(paramName: argumentExpression, message: $ " {argumentExpression} ({argument}) cannot be less than {lowExpression} ({low}).");  
  8.         }  
  9.         if (argument > high) {  
  10.             throw new ArgumentOutOfRangeException(paramName: argumentExpression, message: $ "{argumentExpression} ({argument}) cannot be greater than {highExpression} ({high}).");  
  11.         }  
  12.     }  
  13.     public static void NotNull < T > (T argument,  
  14.         [CallerArgumentExpression("argument")] string argumentExpression = null)  
  15.     where T: class {  
  16.         if (argument == nullthrow new ArgumentNullException(paramName: argumentExpression);  
  17.     }  
  18. }  
  19. // CallerArgumentExpression: convert the expressions to a string!    
  20. Verify.NotNull(array); // paramName: "array"    
  21. // paramName: "index"    
  22. // Error message by wrong Index:     
  23. "index (-1) cannot be less than 0 (0).", or  
  24. // "index (6) cannot be greater than array.Length - 1 (5)."    
  25. Verify.InRange(index, 0, array.Length - 1);  
Status: Prototype
Less code and more readable error message.
Again, there is nothing new here.
Technique behind
Data annotation.
My personal opinion:
I give this feature a 5. Yes, please use it to make a better error message.
I will only discuss the below features in brief.

Default in deconstruction

Status: Implemented
Allows the following syntax (int i, string s) = default; and (i, s) = default.
  1. (int x, string y) = (defaultdefault); // C# 7  
  2. (int x, string y) = default;               // C# 8  
A lot of discussions (Microsoft developers) wish to change the syntax to (int i, string s) any= default; because here you are introducing a new variable.
Relax ordering of ref and partial modifiers,
Status: In Progress
Allows the partial keyword before ref in the class definition.
  1. public ref partial class { } // C# 7  
  2. public partial ref class { } // C# 8  

Null Coalescing Assignment

Status: In Progress
Simplifies a common coding pattern where a variable is assigned a value if it is null.
It is common to see the code of the form:
  1. if (variable == null)  
  2. {  
  3.   variable = expression; // C# 1..7  
  4. }  
  5. variable ??= expression; // C# 8 

Alternative interpolated verbatim strings

Status: Master
This proposal will extend object initializers to allow @$"hello" as a verbatim interpolated string, compared to $@"hello" (current interpolated verbatim string).
  1. var file = $@"c:\temp\{filename}"; // C# 7  
  2. var file = @$"c:\temp\{filename}"; // C# 8  
I will consider this as a fixed bug and not a new feature, that's why I will not discuss it further.

Using declarations

Enhances the ‘using’ operator to use with Patterns and makes it more natural. 
Status: Prototype
  1. // C# Oldy Style  
  2. using (var repository = new Repository())    
  3. {    
  4. // repository is disposed here!    
  6. // vs.C# 8    
  8. using var repository = new Repository();    
  9. Console.WriteLine(repository.First());    
  10. // repository is disposed here!  
Disposable ref structs
Allows you to use ref structs/read-only ref struct with ‘using’ pattern.
Pattern-based using for ref struct
  1. ref struct Test {  
  2.    public void Dispose() { ... }  
  3. }  
  4. using var local = new Test();  
  5. // local is disposed here!  

Generic attributes

Allows the generic type in the C# ‘Attributes’.
Status:In Progress
Single Responsibility Principle (SRP).
  1. public class GenericAttribute<T> : Attribute { }  
  2. public class ValidatesAttribute<T> : Attribute {}  
  3. [Validates<string>]  
  4. public class StringValidation {}  
  5. [Validates<int>]  
  6. public class IntegerValidation{}  
This feature is also coming from the community. A ten-year-old link from the community for this feature:  https://stackoverflow.com/questions/294216/why-does-c-sharp-forbid-generic-attribute-types

Static Local Functions

Allows you to add the 'static' modifier to the local functions.
Status:In Preview
  1. int AddFiveAndSeven()  
  2. {  
  3.   int y = 5; int x = 7;  
  4.   return Add(x, y);  
  5.   static int Add(int left, int right) => left + right;  
  6. }  

This feature will help you to fix the warning so that it does not capture reference to any variables from the enclosing scope.


C# 8 has many useful new features, which are well accepted among the community; unfortunately, the innovation is still low and does not meet many developer's expectations.
The most upcoming new features are very useful as shown in the chart below “C# 8 Features”, the well-scored feature can make your code better, safer. and cleaner.
C# 8 Features

Thank you for your patience to read this article. You have read an overview of the C# 8 proposed features with their pros and cons, and I hope that will help you to be better oriented to use them in the future.