What’s new in .NET 5 and C# 9

Microsoft released .NET 5 and C# 9 on November 10, 2020. The .NET 5 release is a very important milestone for the .NET ecosystem making a definite step forward from the classic .NET Framework. In this post, I will be sharing all the latest innovations .NET 5 and C# 9 are bringing to .NET developers in 2021.

What's new .NET 5?

.NET 5 is effectively the convergence between .NET Core 3.1 and .NET Standard 2.1.

It's the end of the road for the classic .NET Framework 4.8. Microsoft will continue to support the framework until Windows will be shipped but all future innovations will be only implemented in .NET 5 and future releases. 

The goal is to have a single unified .NET framework running in all platform, a single SDK with the ability to support development of any kind of application workflow (desktop, web, mobile, ...).

Microsoft is planning to release a new major version of .NET and C# every year in November.

.NET 5

This is a list of some of the key innovations available in .NET 5:

  • Unified .NET SDF experience with a single BCL
  • Cross-Platform support (Windows, Linux, MacOS, ARM64)
  • Better support for containers in the runtime
  • Cloud-native support
  • Support for the webassembly binary format
  • Single Exe and Assembly Trimming
  • Massive performance improvements
  • ClickOnce deployment
  • Smaller images for better microservices
  • Tey: opinionated .NET microservices & orchestration tools
  • REST and gRPC API with productive tools & debugging
  • C# 9, F# 5
  • Cross-Platform Native UI (MAUI)
  • Cross-Platform Web UI (Blazor)

Getting Started with C# 9

To get started with C# 9 install the following tools:

  • Visual Studio 2019, Visual Studio Code or the Rider IDE
  • .NET 5 SDK

Create a project targeting .NET 5 and the compiler will immediately use C# 9 as the default version.

In fact, with the new tooling, the default C# language is inferred by the target framework of your project. Of course, you can always override the C# language version by setting the Language tag in the csproj.

C# 9 is only officially support in .NET 5 but many features can still be used in .NET Framework. 

C# 9 Language

Top Level Statements

With top level statments, you no longer need to write the class and the static Main method when you create a console application.

You can finally write a simple Hello World program in a single line of code!

Hello World in C# 9

You can use async/await, access command line arguments, define methods and classes using top-level statements.

Top Level Statements in C# 9

Init-Only Properties

Init-Only properties allows you to create immutable properties and still use the object-initializer syntax to initialize the object.

Init-Only Properties


Positional records provide an extremely succint way to define an immutable object with value type semantics. All the methods for equality, copy constructor, deconstructor, ToString are implemented for you by the compiler. 

Positional Records in C# 9

A new with expression, provide a simple way of cloning a record and make changes to some properties.

With Expression in C# 9

Records can be named rather than positional, have custom constructors and also support inheritance. Watch the Master C# 9 webinar for more details.

Target-Typed Conditional Expression

The compiler is now able to infer the target type correctly when conditional expressions return different sub-types.

Target-Type Conditional Expression

Covariant Returns

Covariant returns allows you to override a method using a more specialized type as a return type. This helps to remove unnecessary cast in the code. 

Covariant Returns

Extension GetEnumerator support for foreach

With C# 9 you can now implement GetEnumerator as an extension method. This enable you to make non-enumerable types enumerable with foreach.

GetEnumerator as extension method

Extended Partial methods

Previous limitations for partial methods (method must return void, no access modifiers) no longer apply. Partial methods now can return values, have out parameters and access modifiers. In C# 9, partial declarations with explicit accessibility must have a definition.

Extended Partial Methods

Module Initializers

Module initializers allows you to run code to initialize an assembly. The code runs before any static initialization like static constructors or static properties. 

Module Initializers

Meta-Programming with C# Code Generators

With C# code generators, microsoft is officially adding meta-programming capabilities to the C# language.

This is a compiler feature that enable developers to generate C# code at compile time that will be dynamically added as part of your compilation unit. You can't edit existing code by design but you can only add new code using extensibility points like partial methods and module initializers. 

Code Generators in C# 9

Pattern Matching

You can now use a simple Type as a pattern...

Type Pattern

Microsoft also added support for relational patterns:

Relational Patterns

The not pattern is particularly useful to avoid unnecessary parenthesis:

Not pattern

Patterns matching combinators enable to use and and or keywords to avoid repeating variables in a pattern. The also support flowing type information through the expression.

Patterns matching combinators
Flow type

Lamba discard parameters

With C# 9, you finally can use a single underscore to ignore multiple arguments in lamba expressions.

Lambda Discard Parameters

Target-typed new expression

The compile is now smart in inferring your type from the context. This means you can use new without specifing the type all the time. This feature can be seen as the complement of the var keyword.

Target Typed New Expression

Attributes on Local Functions

You can now add attributes on local functions:

Attributes on Local Functions

Static Anonymous Functions

When matters, you can now improve performance by making your anonymous functions static. Local variables will not be captured.

Static Anonymous Functions

Native-sized integers

Microsoft introduced integers whose size is determined at run-time based on the target platform.

Native-sized integers

Suppress emitting of localsinit flag

You can now tell the compiler not to zero-initialize memory for you.

Suppress emitting of localsinit flag

Function pointers

C# 9 introduce the concept of function pointers to the language. Using function pointers makes the compiler to use a different IL instruction under the covers (calli) compared to when using delegates (callvirt).  

Function Pointers

The syntax allows to explicitely specify the desired calling convention to enable interoperability with other languages and platforms.

Calling Conventions

C# 9 Proposal

Learn more about the syntax in depth by looking at the C# 9 Specification Proposal.

Join the Productive C# Membership

Do you want to stay up-to-date with C# and .NET?
Do you want to join a premium membership with professional C# developers?
Do you want to receive a weekly newsletter with .NET news?
Do you want to get incredible benefits and free licenses from productivity tools?

Learn more about the Productive C# Membership and join us. 

Join the Productive C# Membership

This article is one of the 50 contributions to the forth annual C# advent. Thank you Matthew for the opportunity to share my love for C# with the community.