C# 9
This release is where many modern data modeling patterns became much easier to express.
Back to overview
Section titled “Back to overview”Records
Section titled “Records”Records are a concise way to model immutable, value-like data.
public record Money(decimal Amount, string Currency);Legacy equivalent:
public sealed class Money{ public decimal Amount { get; } public string Currency { get; }
public Money(decimal amount, string currency) { Amount = amount; Currency = currency; }}Records also provide value-based equality by default.
Init-only setters
Section titled “Init-only setters”Init-only setters allow properties to be assigned during object initialization, but not mutated later.
public class Person{ public string FirstName { get; init; } = ""; public string LastName { get; init; } = "";}Usage:
var person = new Person{ FirstName = "Ada", LastName = "Lovelace"};This is often a better fit than fully mutable setters on data models.
Target-typed new
Section titled “Target-typed new”Target-typed new removes repeated type names when the target type is already clear.
Dictionary<string, List<int>> lookup = new();Legacy style:
Dictionary<string, List<int>> lookup = new Dictionary<string, List<int>>();Relational and logical patterns
Section titled “Relational and logical patterns”Relational and logical patterns make range checks more readable.
if (percentage is >= 0 and <= 100){ Console.WriteLine("Valid");}Legacy style:
if (percentage >= 0 && percentage <= 100){ Console.WriteLine("Valid");}Top-level statements
Section titled “Top-level statements”Top-level statements reduce ceremony for small programs, demos, and utilities.
using System;
Console.WriteLine("Hello, modern C#");This feature is convenient for small tools, but many larger applications still prefer explicit Program types for structure and discoverability.