Skip to content

C# 11

The biggest wins in everyday code usually come from raw string literals and required members.

Modernization Overview

Raw string literals are much easier to read when a string contains quotes, braces, JSON, SQL, or regex-like content.

var json = """
{
"name": "Ada",
"role": "Engineer"
}
""";

Legacy style:

var json = "{\"name\":\"Ada\",\"role\":\"Engineer\"}";

Required members ensure important properties are supplied during initialization.

public class ConnectionSettings
{
public required string ConnectionString { get; init; }
public required string DatabaseName { get; init; }
}

Usage:

var settings = new ConnectionSettings
{
ConnectionString = "...",
DatabaseName = "Main"
};

This helps avoid partially initialized objects.

List patterns make it easy to inspect array and list shapes.

if (values is [1, 2, ..])
{
Console.WriteLine("Starts with 1, 2");
}

This is often clearer than manually checking Count and indexing into the collection.

Generic attributes remove the need to pass a Type object in some attribute scenarios.

[MyValidator<Order>]
public class CreateOrderCommand
{
}

This can make attribute usage more strongly typed and easier to refactor.

UTF-8 string literals are useful when APIs work directly with UTF-8 bytes.

ReadOnlySpan<byte> header = "Content-Type"u8;

This can avoid an encoding step compared to starting from a UTF-16 string.