NDepend

Improve your .NET code quality with NDepend

Unveiling the Impressive Features of Upcoming C# 12

C# 12 New Features

Microsoft unveils new features in C# 12 Preview. C# 12 along with .NET 8 will be officially released in November 2023. Let’s explore the latest impressive enhancements in this post.

Primary Constructors syntax now usable on class and struct in C# 12

Since C#9 we have the convenient primary constructor syntax for class record (or just record) and struct record:

C# 12 introduces primary constructors for non-record classes and structs, but it’s important to note that they work differently. Actually the motivation behind their implementation varies:

  • In records, the primary constructor offers a succinct method to generate public read-only properties. This is useful for creating simple immutable objects meant to store states.
  • In C# 12 classes and structs, the primary constructor provides a concise way to generate private fields. Since classes and structs often have internal logic that relies on internal states, the primary constructor aids in initializing these states during construction.

Primary constructors eliminate the need for declaring private fields and manually linking parameter values to those fields in constructor bodies. Say goodbye to that tedious process:

CSharp12 Primary Constructor Motivation

Notice that in non-record classes and structs, properties aren’t automatically generated for primary constructor parameters. You need to create them manually to indicate which data is accessible. This aligns with the typical usage of classes

More about primary constructor can be found in this post: C#12 class and struct Primary Constructors (naming conflict, interaction with other constructors, property, advanced usage of fields generated…).

C# 12 Using directives to alias any types

C# has long supported aliases for namespaces and named types (classes, delegates, interfaces, records, and structs). This feature effectively resolves naming conflicts when using directives may introduce ambiguity. Additionally, it simplifies the usage of complex generic types by providing concise alternatives. However, the language’s growing collection of complex type symbols has created a demand for aliases that are currently not permitted. Consider tuples, nullable and function-pointers, which often have lengthy and intricate textual representations that are cumbersome to write repeatedly and challenging to read. By allowing more aliases in C# 12, developers can assign shorter names to replace these extensive structural forms, thereby enhancing code readability and developer productivity.

C# 12 Default values for lambda expressions

C# 12 boosts lambda expressions by enabling developers to set default parameter values. The syntax resembles that of other default parameters. For instance,  (int val = 10) => val + 1; . The default value 10 is utilized when no value is provided in the lambda call.

C# 12 nameof operator improvement

The nameof operator now works in C# 12 with member names, including static members, initializers and in attributes:

C# 12 Inline arrays

The InlineArrayAttribute has been introduced with .NET 8 and can be used from C# 12 programs. The principal purpose of this attribute is to designate a type as eligible for representation as a contiguous sequence of primitives. The size of an inline array is fixed at compile time. This makes it faster because the exact layout is known by the compiler that generates optimized IL code to access elements of the inline array. Also an inline array is a struct which makes it allocated on the thread stack and not on the heap as with regular .NET arrays. Here is a short program based on .NET 8 inline arrays, notice how inline array element access is similar to regular array element access through inlineArray[i] :

Clearly this C# 12 new feature is a niche one. It is chiefly aimed at utilization by the compiler, the .NET BCL, and select third-party libraries.  But I guess for those that need more performance like in the game industry, inline arrays are welcome.

C# 12 Interceptors

C# 12 interceptors is a powerful – yet strange – new feature that we are going to demonstrate first. Then we’ll go through potential use-cases. To make work this short program you need a C# 12 compatible project with 2 files, Program.cs and MyInterceptors.cs. The csproj must look like this:

Here is the content of Program.cs:

Here is the content of MyInterceptors.cs:

This program outputs:

If we decompile the assembly generated it with ILSpy we can see that calls to Method() have been hijacked by the compiler:

Notice that if you change anything in:

System.Runtime.CompilerServices.InterceptsLocationAttribute(@"C:\Users\pat\source\repos\ConsoleApp170\ConsoleApp170\Program.cs", 3,5)]

the compiler emits an error because online a valid triple of (absolute file path + line + column) can work.

Why are they planning such a weird feature in C# 12? The primary rationale is Ahead-Of-Time compilation (AOT) that becomes first citizen with .NET 8. While interceptors aren’t exclusively tailored to AOT, their design unmistakably takes AOT into account. Through the employment of interceptors, it becomes feasible to transform code that previously posed challenges for AOT into versions generated directly from the source.

The GeneratedCode class will be generated by a tool and developer won’t have to even change their code.

Conclusion

This article delves into new features introduced in C# 12 Preview. Microsoft is dedicated to enhancing the C# language, prioritizing efficiency and developer-friendliness. Expect further advancements in the near future.

 

My dad being an early programmer in the 70's, I have been fortunate to switch from playing with Lego, to program my own micro-games, when I was still a kid. Since then I never stop programming.

I graduated in Mathematics and Software engineering. After a decade of C++ programming and consultancy, I got interested in the brand new .NET platform in 2002. I had the chance to write the best-seller book (in French) on .NET and C#, published by O'Reilly and also did manage some academic and professional courses on the platform and C#.

Over my consulting years I built an expertise about the architecture, the evolution and the maintenance challenges of large & complex real-world applications. It seemed like the spaghetti & entangled monolithic legacy concerned every sufficiently large team. As a consequence, I got interested in static code analysis and started the project NDepend in 2004.

Nowadays NDepend is a full-fledged Independent Software Vendor (ISV). With more than 12.000 client companies, including many of the Fortune 500 ones, NDepend offers deeper insight and full control on their application to a wide range of professional users around the world.

I live with my wife and our twin kids Léna and Paul in the beautiful island of Mauritius in the Indian Ocean.

Leave a Reply

Your email address will not be published. Required fields are marked *