What’s new in C# 9.0

Parag Sarin
3 min readNov 24, 2020
  • Top 5 new CSharp 9 features released on Nov 10 2020
  • Require .NET 5 Framework and Visual Studio version 16.8.1 to use these new c#9.0 features and the sample application

C# 9.0 adds the following features and enhancements to the C# language.

Top-level programs

Top-level statements remove unnecessary ceremony from many applications like console applications.

//These 12 line of code

using System;

namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(“Hello World!”);
}
}
}

Now all the boilerplate code is not needed. Below 2 lines replace 12 lines of above boilerplate code.

//To these 2 line of code

using System;
Console.WriteLine(“Hello World! — I am Top Level Program”);

Init-only properties

Starting with C# 9.0, you can create init accessors instead of set accessors for properties and indexers. Init-only properties are great if you want to make individual properties immutable

class InitOnlyProps
{
public string Name { get; init; }

public string Address { get; set; }

public InitOnlyProps()
{
Name = “anonymous”;
Address = “none”;
}

public InitOnlyProps(string newName, string newAddress)
{
Name = newName;
Address = newAddress;
}

private void ChangeName(string newName, string newAddress)
{
//Not allowed
//Name = newName;
Address = newAddress;
}

}

InitOnlyProps props1 = new InitOnlyProps();
props1.Address= “”;
//*****Not allowed*****
//props.Name=”John”

//Allowed
InitOnlyProps props2 = new InitOnlyProps { Name = “John”, Address = “USA” };

//Allowed
InitOnlyProps props3 = new InitOnlyProps (“John”, “USA” );

Target-typed new expressions

In C# 9.0, you can omit the type in a new expression when the created object's type is already known

InitOnlyProps shorthandinstantiation = new(“John”, “USA”);

Improved pattern matching

Pattern matching(feature of C#8.0) is achieved by using the switch operator

Several new kinds of patterns have been added in C# 9.0

Relational pattern matching in switch expression

>, <, >=, <=
Logical pattern(range) matching in switch expression

and, or, not

foreach (var temp in summary)
{
/* Not super cool code below
if (temp.Temp < 0)
{
temp.Summary = “Super Cold”;
}
else if (temp.Temp > 50)
{
temp.Summary = “Super Hot”;
}
else if (temp.Temp > 30 && temp.Temp <50)
{
temp.Summary = “Hot”;
}
else
{
temp.Summary = “I can live with it”;
}
*/

//New pattern matching code
temp.Summary = temp.Temp switch
{
< 0 => “Super Cold”,
> 50 => “Super Hot”,
> 30 and < 50 => “Hot”,
_ => “I can live with it”
};

}

Records

Record types make it easy to create immutable reference types in .NET. Historically, .NET types are largely classified as reference types (including classes and anonymous types) and value types (including structs and tuples). While immutable value types are recommended, mutable value types don’t often introduce errors. Value type variables hold the values so changes are made to a copy of the original data when value types are passed to methods.

Init-only properties are great if you want to make individual properties immutable. If you want the whole object to be immutable and behave like a value, then you should consider declaring it as a record:

//similar to class with some caveats
//Immutable
//ToString implementation is different
//Equals would give diff results for record and class

IdRecords id1 = new (“Parag”, “USA”);
//Not allowed
//id1.Address = “1233”;

Console.ForegroundColor = ConsoleColor.DarkMagenta;

IdRecords id2 = new(“Parag”, “USA”);

InitOnlyProps classid1 = new InitOnlyProps(“Parag”, “USA”);

InitOnlyProps classid2 = new InitOnlyProps(“Parag”, “USA”);

Console.WriteLine($”ToString record — {id1.ToString()}”);

Console.WriteLine($”ToString class — {classid1.ToString()}”);

Console.WriteLine($”Equals record — {id1.Equals(id2)}”);

Console.WriteLine($”Equals class — {classid1.Equals(classid2)}”);

Sample code to explore important new c#9.0 features can be found on github(link below).

--

--