In past five years, Microsoft had made a rapid enhancements in C# by introducing a plenty major features with every new version, As planed, C# 9.0 will be officially released with .NET 5 on November 2020. So we will dive into C# 9.0 new features that released on 20 may 2020 as a Preview. 1- Top-level programs Presently, in C# coding a simple program requires a noticeable amount as initial code as following : System; { { Console.WriteLine( ); } } using class Program ( ) static void Main "Hello World!" C# 9.0 introduces feature that, allows you to code your main program (Any statement is allowed) at the top level instead immediately after statements and no need to declare any namespace, class or main method.As per C#, you must have only one entry point for your program so, you can exclusively do this in only one file as following: Top-level programs using System; Console.WriteLine( ); using "Hello World!" 2- Target-typed expressions new expressions always required a type to be specified (except for implicitly typed array or anonymous types) as following. new Point point = Point( , ); Dictionary< , List< >> field = Dictionary< , List< >>() { { , List< >() { , , } } }; items = [] { , , }; example = { Greeting = , Name = }; // Instantiation of point object new 3 5 // Instantiation of dictionary object string int new string int "item1" new int 1 2 3 // implicitly typed array var new 10 20 30 // Instantiation of anonymous types var new "Hello" "World" In C# 9.0 the type is optional if there’s a clear target type that the expressions is being assigned to as following: Point point = ( , ); Dictionary< , List< >> field = () { { , () { , , } } }; XmlReader.Create(reader, () { IgnoreWhitespace = }); // initialization without duplicating the type. new 3 5 string int new "item1" new 1 2 3 // the type can be inferred from usage. new true 3- Pattern Matching Improvements C# 7 introduced basic pattern matching features then, C# 8 extended it with new expressions and patterns. By the time, C# 9.0 introduced new pattern enhancements as following: declaring default identifier for type matching not required vehicle { Car { Passengers: } => m + m, Car { Passengers: } => m, Car { Passengers: } => m - m, Car _ => m - m, }; // Before switch 0 2.00 0.50 1 2.0 2 2.0 0.50 2.00 1.0 vehicle { Car { Passengers: } => m + m, Car { Passengers: } => m, Car { Passengers: } => m - m, Car => m - m, }; // C# 9.0 switch 0 2.00 0.50 1 2.0 2 2.0 0.50 // no identifier for default type matching 2.00 1.0 Relational patterns C# 9.0 introduces supporting the relational operators , , , and patterns as following: < <= > >= => age { < => LiftStage.Prenatal, < => LifeStage.Infant, < => LifeStage.Toddler, < => LifeStage.EarlyChild, < => LifeStage.MiddleChild, < => LifeStage.Adolescent, < => LifeStage.EarlyAdult, < => LifeStage.MiddleAdult, _ => LifeStage.LateAdult, }; LifeStage ( ) public static LifeStageAtAge age int switch 0 2 4 6 12 20 40 65 Logical patterns C# 9.0 introduces supporting the logical operators , , and patterns as following: and or not => age { < => LiftStage.Infant, >= and < => LifeStage.Child, >= and < => LifeStage.Teenager, >= => LifeStage.Adult, }; => x >= and <= or >= and <= or >= D and <= D; LifeStage ( ) public static LifeStageAtAge age int switch 2 2 12 12 18 18 ( ) bool IsValidPercentage x object is 0 100 // integer tests 0F 100F // float tests 0 100 // double tests Also is going to be convenient in if-conditions containing is-expressions where, instead of unwieldy double parentheses. not (!(e )) { ... } (e not ) { ... } // before if is null // C# 9.0 if is null 4- Covariant return types By introducing feature in C# 9.0, you are permitted to override a method or a read-only property to return a more derived return type than the method or property overridden as following: covariant return types ... { { class Compilation Compilation ( )... } class CSharpCompilation : Compilation virtual CreateWithOptions Options options CSharpCompilation ( )... } override CreateWithOptions Options options 5- Extending Partial Methods C# has limited support for developers splitting methods into declarations and definitions/implementations. Partial methods have several restrictions: Must have a return type. void Cannot have or parameters. ref out Cannot have any accessibility (implicitly ). private One behavior of methods is that when the definition is absent then the language will simply erase any calls to the method . partial partial { ; { M(GetIt()); } => ; } partial class D ( ) partial void M message string ( ) void Example // Call to M and GetIt erased at compile time ( ) string GetIt "Hello World" C# 9.0 extends methods to remove most of the existing restrictions around methods as following: partial partial allow them have or . ref out allow return types non-void allow any type of accessibility ( , , etc ..). private public Such partial declarations would then have the added requirement that a definition must exist. That means the language does not have to consider the impact of erasing the call sites. When a method has an explicit accessibility modifier though the language will require that the declaration has a matching definition even when the accessibility is as following: partial private { ; ; ; } { { } } partial class C // Okay because no definition is required here ( ) partial void M1 // Okay because M2 has a definition ( ) private partial void M2 // Error: partial method M3 must have a definition ( ) private partial void M3 partial class C ( ) private partial void M2 Further the language will remove all restrictions on what can appear on a partial method which has an explicit accessibility. Such declarations can contain return types, or parameters, modifier, etc... These signatures will have the full expressivity of the C# language. non-void ref out extern { ; } { { ... } } partial class D // Okay ( ) internal partial bool TryParse s, i string out int partial class D ( ) internal partial bool TryParse s, i string out int 6- Init-only properties In C#, it is not possible to initialize immutable properties of a class by as following. Object initialize { FirstName { ; } LastName { ;} } // immutable properties public class Person public string get public string get // can't be initialized using Object initialize // var person = new Person // { // FirstName = "Ahmed", // LastName = "Yousif" // } on the other, hand if we want to initialize them using we have to make these properties mutable that, open the door for manipulating it as following: Object initialize { FirstName { ; ; } LastName { ; ; } } ... person = Person { FirstName = , LastName = } person.FirstName = // mutable properties public class Person public string get set public string get set var new "Ahmed" "Yousif" // property can be changed "Mohamed" By introducing C# 9.0 solve that hard equation! Init-only properties C# 9.0 introduces an accessor that allow initializing property only during object initialization as following: init { FirstName { ; init; } LastName { ; init; } } ... person = Person { FirstName = , LastName = } public class Person public string get public string get var new "Ahmed" "Yousif" // manipulating property after initialization won't be allowed // person.LastName = "Mohamed" 7- Records is a great feature for making individual properties immutable.But what if we want to make the whole object immutable, Here we can highlight the importance of introducing feature. by using keyword before keyword as following: Init-only properties Record data class data { FirstName { ; init; } LastName { ; init; } } public class Person public string get public string get So, in this case we immuted the whole object which, consider as declaring a record state. records can be shorthand the declaration as following: data { FirstName; LastName; } // exactly the same declaration before public class Person string string If you want to add a private field,you must add modifier explicitly: private firstName; private string 8- With-expressions Now, if we want to change the state of immutable object how we can do it! in this case we have to copy the exist object with updated values to represent a new state. by introducing feature we can achieve it so easy as following: With-expressions person = Person { FirstName = , LastName = } anotherPerson = person with { LastName = }; var new "Ahmed" "Yousif" // copy person object with update LastName var "Ali" feature uses object initializer syntax to set state what’s different in the new object. With-expressions 9- Value-based equality feature allows you to compare two instances of Class value base equality same as by comparing all properties in the object using static method. on the other hand if you want check reference base equality you can use static method as following: Value-based equality Record Structs Object.Equals(object, object) Object.ReferenceEquals(object, object) person = Person { FirstName = , LastName = } anotherPerson = person with { LastName = }; var new "Ahmed" "Yousif" // copy person object and with same lastname var "Yousif" // they have the same values so will be true // Equals(person, anotherPerson) // they aren’t the same object so will be false // ReferenceEquals(person, anotherPerson) 10- Positional records Let's say we want to apply positional approach to a record class to get benefits of positional deconstruction so, in this case you have to explicitly implement constructor and deconstructor of the record as following: data { FirstName; LastName; => (FirstName, LastName) = (firstName, lastName); => (firstName, lastName) = (FirstName, LastName); } public class Person string string ( ) public Person firstName, lastName string string ( ) public void Deconstruct firstName, lastName out string out string But there's a good news by introducing C# 9.0 there is a shorthand expressing exactly the same thing. ; // equivalent to previous one data class ( ) public Person FirstName, LastName string string now you can deconstructing your object as following: person = Person( , ); (fName, lName) = person; var new "Ahmed" "Yousif" // positional construction var // positional deconstruction And much more features… So, the best place to check out the last updates of upcoming features for C# 9.0 is the on the C# compiler Github repo. Language Feature Status