Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ


Choose your language

InfoQ Homepage News What's New in C# 12: Primary Constructors, Collection Expressions, and More

What's New in C# 12: Primary Constructors, Collection Expressions, and More

This item in japanese

As part of the .NET 8 launch, on November 14th Microsoft unveiled the new features of C# 12, the latest version of the popular .NET programming language. As announced the most notable improvements include collection expressions, primary constructors for all classes and structs, syntax to alias any type, and default parameters for lambda expressions.

C# 12 introduces the extension of primary constructors to include this feature in all classes and structs, not limited to records only. This enhancement allows the definition of constructor parameters directly within the class declaration.

The primary constructor parameters find versatile applications, serving as arguments for base() constructor invocations, encouraging member field or property initialisation, referencing within instance members, and facilitating dependency injection by eliminating boilerplate code.

public class BankAccount(string accountID, string owner)
    public string AccountID { get; } = accountID;
    public string Owner { get; } = owner;

    public override string ToString() => $"Account ID: {AccountID}, Owner: {Owner}";

(Source: Microsoft .NET DevBlog, Announcing C# 12)

The primary constructor parameter operates as a class-wide scoped parameter, applicable to various types, including class, struct, record class, and record struct. Notably, when applied to record types, the compiler automatically generates public properties for each primary constructor parameter, simplifying member management for record structures.

Collection expressions are also introduced, which simplifies the syntax for creating various collections, providing a unified approach. As stated, this eliminates the need for distinct syntax when initializing arrays, lists, or spans. The compiler generates efficient code, optimizing collection capacity and avoiding unnecessary data copying.

int[] x1 = [1, 2, 3, 4];
int[] x2 = [];
WriteByteArray([1, 2, 3]);
List<int> x4 = [1, 2, 3, 4];
Span<DateTime> dates = [GetDate(0), GetDate(1)];
WriteByteSpan([1, 2, 3]);

Additionally, a new spread operator simplifies the inclusion of elements from multiple collections. The team stated that this feature is open to feedback for potential future expansions, including dictionaries and support for var (natural types) in upcoming C# versions.

int[] numbers1 = [1, 2, 3];
int[] numbers2 = [4, 5, 6];
int[] moreNumbers = [.. numbers1, .. numbers2, 7, 8, 9];
// moreNumbers contains [1, 2, 3, 4, 5, 6, 7, 8, ,9];

Regarding performance in C# 12, two new features ref readonly parameters and inline arrays are introduced to enhance raw memory handling and boost application performance. The ref readonly parameters offer an adaptable approach to passing parameters by reference or value, particularly beneficial when a method needs the memory location of an argument without modification.

Inline arrays, a struct-based, fixed-length array type, provide a secure way to work with memory buffers, improving performance in scenarios involving arrays of structures without the need for unsafe code. These additions empower developers to optimize their code for increased efficiency.

public struct Buffer
    private int _element0;

// Usage
var buffer = new Buffer();

for (int i = 0; i < 10; i++)
    buffer[i] = i;

foreach (var i in buffer)

Furthermore, two experimental features are introduced, the Experimental attribute and interceptors. The Experimental attribute clarifies the status of experimental features, requiring the calling code to be marked as experimental to avoid errors. Interceptors allow the redirection of method calls, offering optimization possibilities.

While interceptors are not recommended for production due to potential changes, both features underscore the importance of using the Experimental attribute for clarity and consistency in experimental code.

Other available C# 12 features are the possibility of adding optional parameters to lambda expressions and the using alias directive to alias any sort of type (not just named types). This allows developers to create semantic aliases for tuple types, array types, pointer types, or any other unsafe types.

Func<int, int, bool> testForEquality = (x, y) => x == y;

The original announcement blog post comment section received a few interesting ideas about improvements and suggestions of C# language, and based on different threads and forums overall community feedback is positive.

Official dotnet YouTube channel also published the 35-minute recording of the .NET 8 launch session with the title What's New in C# 12 and it is highly recommended for developers to watch it.

Readers can find more about the available C# 12 features on the official language documentation page. Developers can get it by downloading .NET 8, the latest Visual Studio, or Visual Studio Code’s C# Dev Kit.

About the Author

Rate this Article