Skip to content

C# 13

This release matters most when working close to allocations, spans, or generated code.

Modernization Overview

C# 13 expands params beyond array types.

public static void Log(params ReadOnlySpan<string> items)
{
foreach (var item in items)
Console.WriteLine(item);
}

Legacy style:

public static void Log(params string[] items)
{
foreach (var item in items)
Console.WriteLine(item);
}

In the right scenarios, the newer approach can avoid allocations and fit span-based APIs better.

When the target of a lock statement is System.Threading.Lock, the compiler can generate code that uses the new lock type more directly.

private readonly System.Threading.Lock _gate = new();
lock (_gate)
{
// protected section
}

This keeps the familiar lock syntax while enabling the newer semantics.

Method groups participate more naturally in type inference in additional scenarios.

var parser = int.Parse;

This reduces the need for explicit delegate type declarations in some assignments.

Partial properties and indexers can now be split across partial type declarations.

public partial class Sample
{
public partial string Name { get; set; }
}
public partial class Sample
{
private string _name = "";
public partial string Name
{
get => _name;
set => _name = value;
}
}

This is mainly useful in source generation and similar advanced scenarios.

C# 13 expands what ref struct types can do, including interface implementation in supported cases.

public ref struct TokenReader : IDisposable
{
public void Dispose()
{
}
}

This improves the expressiveness of stack-only types and related low-level APIs.