C# 12
It combines readability improvements with some targeted performance-oriented tools.
Back to overview
Section titled “Back to overview”Primary constructors
Section titled “Primary constructors”Primary constructors bring constructor parameters directly into the type declaration.
public class Worker(ILogger<Worker> logger){ public void Run() => logger.LogInformation("Running");}Legacy style:
public class Worker{ private readonly ILogger<Worker> _logger;
public Worker(ILogger<Worker> logger) { _logger = logger; }
public void Run() => _logger.LogInformation("Running");}This feature is concise, but explicit constructors can still be clearer in more complex types.
Collection expressions
Section titled “Collection expressions”Collection expressions provide a uniform syntax for arrays and many collection targets.
int[] values = [1, 2, 3];List<string> names = ["Ada", "Grace"];var combined = [..names, "Linus"];Legacy style:
int[] values = new[] { 1, 2, 3 };List<string> names = new List<string> { "Ada", "Grace" };Inline arrays
Section titled “Inline arrays”Inline arrays are aimed at specialized low-level scenarios where a small fixed-size buffer is useful.
[System.Runtime.CompilerServices.InlineArray(8)]public struct Buffer8{ private byte _element0;}This is not a general-purpose replacement for arrays, but it is relevant in tight performance-sensitive code.
Alias any type
Section titled “Alias any type”Alias any type makes complex tuple or array signatures easier to name.
using Measurement = (double Value, string Unit);
Measurement length = (12.5, "cm");This can improve readability when the same complex type appears in multiple places.
Ref readonly parameters
Section titled “Ref readonly parameters”ref readonly parameters allow passing large structs efficiently while preventing mutation.
public static decimal Sum(in Money value1, in Money value2){ return value1.Amount + value2.Amount;}This is most useful for larger value types or performance-sensitive APIs.