What's New in C# 9? A Guide to the Key Features
A deep dive into the major features introduced in C# 9 with .NET 5, including records, top-level statements, and improved pattern matching. Learn how these additions can make your code more concise and expressive.
C# 9, released alongside .NET 5, brought a host of powerful new features to the language, with a strong focus on simplifying code and enabling more modern, data-centric programming patterns. The additions of records and top-level statements, in particular, have fundamentally changed how developers can write C#.
Let's explore the most impactful features of C# 9.
1. Records: The New Way to Model Data
This is the headline feature of C# 9. Records are a new reference type that provides a simplified syntax for creating immutable data objects. The compiler automatically generates several boilerplate methods for you, making them perfect for DTOs (Data Transfer Objects) and other data-centric classes.
The Old Way:
public class Person
{
public string FirstName { get; init; }
public string LastName { get; init; }
public Person(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
// Plus manual implementation of Equals, GetHashCode, ToString...
}
The New Way with Records:
public record Person(string FirstName, string LastName);
With this single line, the compiler generates:
- A constructor.
init-only
properties (see below).- Value-based equality (
Equals
andGetHashCode
are implemented for you). - A clean
ToString()
implementation. - A deconstructor.
Records also support a non-destructive mutation syntax called with
expressions:
var person1 = new Person("John", "Doe");
var person2 = person1 with { LastName = "Smith" }; // Creates a new record
2. Init-Only Setters
Closely related to records, init-only
setters allow you to create immutable properties that can only be set during object initialization. This is a great alternative to making properties read-only and forcing all initialization through the constructor.
public class Person
{
public string FirstName { get; init; }
public string LastName { get; init; }
}
// You can set the properties in an object initializer
var person = new Person { FirstName = "Jane", LastName = "Doe" };
// But you can't change them later (this would be a compile error)
// person.FirstName = "Janet";
3. Top-Level Statements
This feature dramatically simplifies the code needed for simple programs and utilities. You can now write your executable code directly in your Program.cs
file, without needing to manually define a Program
class and a Main
method.
The Old Way:
using System;
namespace MyConsoleApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
}
The New Way:
// Program.cs
using System;
Console.WriteLine("Hello, World!");
The compiler automatically generates the Program
class and Main
method for you behind the scenes. This makes C# a much more approachable language for beginners and is fantastic for writing simple scripts.
4. Improved Pattern Matching
C# 9 continues to enhance pattern matching with several new patterns:
- Relational Patterns: You can now use relational operators (
<
,>
,<=
,>=
) in patterns.public string GetGroup(int age) => age switch { < 18 => "Child", >= 18 and < 65 => "Adult", >= 65 => "Senior" };
- Logical Patterns: You can combine patterns with
and
,or
, andnot
.if (c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z')) { // It's a letter }
Conclusion
C# 9 was a significant release that focused on making C# more concise, expressive, and easier to learn. Records have provided a much-needed syntax for data-focused programming, while top-level statements have lowered the barrier to entry for new developers. These features have laid the groundwork for the even more simplified syntax that would come later in C# 10's Minimal APIs.