C# team will keep diving C# into the innovation world and adding more new features. The most C# 9 features are planned to be useful for all C# developers. The supported Microsoft .Net community will continue engaging us (C#Corner, Reddit, SO: Non-Microsoft developers) in the C# development process so that the compiler developers, can get early feedback for their code changes.
Summarize Current State for us
Finally, Microsoft does not want to make C# driven by Community (Votes Driven), and they have left the final decision to the C# Design team.
I hope that Mads Torgersen can change this truth, and he can improve the connection between the different C# communities.
Important!
C# 9 ships with .Net 5. Records and DU are the main features for C# 9. Unfortunately, DU is moved from C# 9 plan to C# 10. It seems to be that Microsoft does not have enough resources to finish the initial plan.
C# 9 has two Core Concerns
1) Simplicity in common coding scenarios
2) More supporting the for the immutable data structures
C# 9 Core Concerns
Simplicity: Just make the thing simpler!
Immutability: More support for the Immutable data types like Records, read-only data structures, and empowering the pattern matching.
In this article, I will talk about the most C# 9 Candidates.
1. Nominal records
2. Records as a collection of features
3. Natural value equality
4. [Proposal] Improve overload resolution for delegate compatibility
5. Champion: relax ordering constraints around `ref` and `partial` modifiers on type declarations
6. Champion: Simplified parameter null validation code
7. Top level statements and member declarations (embrace scripting dialect)
8. Generators without language change
9. Champion: Module Initializers
10. Champion "Target-typed `new` expression"
11. Proposal: Target typed null coalescing (`??`) expression
12. Champion: target-typed conditional expression
13. Champion “Nullable-enhanced common type”
14. Champion “Permit attributes on local functions”
15. Champion “Covariant Return Types”
16. Champion “Records”
17. Primary Constructors
18. Champion "pattern-based `with` expressions"
19. Champion “Native-Sized Number Types”
20. Champion “and, or, and not patterns”
21. Proposal: allow comparison operators in switch case labels C#
22. Proposal: Use static keyword for lambdas to disallow capturing locals and parameters
23. Champion: Type Patterns
24. Champion “Lambda discard parameters”
25. Proposal: improvements to nullable reference types
26. Support for method argument names in nameof()
I will start with the most important feature for the C# 9
Records
Records can be of Value Type or Reference Type. Records are useful to represent complex data with many properties, like a database record or some model entity, DTO’s, etc.
• Read-only properties => Immutable Type
• Equality implementations => Structural Equality & Referential Equality
• Pattern-matching support => type pattern, switch pattern etc.
In my previous articles, I have described the Positional Records and the Nominal Records. If you are not familiar with those terms, don’t worry: I will simplify them as best I can. Basically, C# allows us to write the code in a positional or nominal style. Let us first take a look at the Object initializers.
Object initializers allows to create an object in a very flexible and readable format:
Microsoft Example:
- // The following code:
- public class Person
- {
- public string FirstName { get; set; }
- public string LastName { get; set; }
- }
- // Can be created as follows
- new Person
- {
- FirstName = "Scott",
- LastName = "Hunter"
- }
- p.FirstName = “Alugili” // Works no Error!
"The one big limitation today is that the properties have to be mutable for object initializers to work" Init-only properties fix that!
- public class Person
- {
- public string FirstName { get; init; }
- public string LastName { get; init; }
- }
- Person p = new Person
- {
- FirstName = "Scott",
- LastName = "Hunter"
- }
- p.FirstName = “Alugili” // Error !
Positional Records and the Nominal Records
C# allows you to write the code with a positional or nominal code style. Object initializer belongs to the nominal category. Until C# 8, the nominal category is restricted because it required writable properties. The introduced “init” accessor removes this limitation in C# 9.
Nominal Records
Nominal data is defined as data that is used for naming or labeling variables.
Example:
- data class User {string Name, int Age};
- var user = new User {Name = "Bassam", Age= 43};
- var copyUser = user with {Name = "Thomas"};
The variables in ordinal data are listed in an ordered manner.
- data class User(string Name, int Age);
- var user = new User("Bassam", 43);
- // Change the data
- var copyUser = user with {Name = "Thomas"};
- // Deconstruction
- (string name, int age) = user;
- // Pattern matching (Type Pattern)
- if (user is ("Bassam", _))
- Console.Write($“My Name is {user.Name}”);
Structural Equality & Referential Equality
Usually, records are compared by structure and not by reference. In C# 9 we can make both approaches.
Referential Equality (Identity)
Means that the pointers for two objects are the same when they have the same memory location, which leads us to the fact that pointers reference to the same object.
Identity: determines whether two objects share the same memory address.
Structural Equality
Means that two objects have equivalent content.
Equality: determines if two objects contain the same state.
Example:
- data class User (string name, int age);
- public static void Main(){
- User user = new User( "Bassam", 43);
- User user2 = new User( "Bassam", 43);
- if (Equals(user, user2))
- {
- Console.WriteLine("Structural Equality !");
- }
- if (ReferenceEquals(user, user2))
- {
- Console.WriteLine("!!!! The code will not execute!!!!");
- }
Structural Equality!
Besides, Records support inheritance, which makes Records in C# unique and varies from the most functional programming languages and F#.
Inheritance in Records Example
- abstract data class User {string name, int age};
- data class SuperUser:User {bool IsAdmin};
- var user = new SuperUser(FirstName = "Bassam", Age= 43, IsAdmin true);
Inheritance - Records mutation and “with” expression
- // The runtime- type is preserved after the coping, consider the below example:
- abstract data class User {string name, int age};
- data class SuperUser:User {bool IsAdmin};
- var user = new SuperUser(Name = "Bassam", Age= 43,IsAdmin true);
- var copyUser = user with {Name = "Thomas"};
- Console.WriteLine(copyUser.GetType().Name); // Output: SuperUser
Improve overload resolution for delegate compatibility
This feature allows the below code to compile:
- delegate void MyAction<T>(T x);
- void Y(long x) { }
- void D(MyAction<int> o) { }
- void D(MyAction<long> o) { }
- void T()
- {
- D(Y); // Ambiguous between both D calls, despite the fact that `void
- D(MyAction<int>)` is not a valid target.
- }

Paul MarchPosted Sep 1, 2020, 10:20 AM
This is plagiarism from https://devblogs.microsoft.com/dotnet/welcome-to-c-9-0/
Faisal PathanPosted Jun 1, 2020, 3:29 AM
Very interesting, Thanks for sharing with c# lovers like me ??
Nandha NandhuPosted May 30, 2020, 11:38 AM
Thanks for sharing this article. So many changes available in c# 9. This was very useful, whenever I write the code hereafter.
Mahesh ChandPosted May 30, 2020, 10:45 AM
Thanks Bassam for keeping all of us informed about C# language updates and releases.
Rikam PalkarPosted May 30, 2020, 10:17 AM
So informative, Really good job in keeping most of features together.