Last month, together with Visual Studio 17.7 Preview 3, Microsoft released new preview features for C# 12. The new language version will be the default for .NET 8, expected to be released later this year.
The latest available features for C# 12 are inline arrays and interceptors. Inline arrays, often utilized by the runtime team and various library creators, are tools to enhance the speed of your applications. They allow developers to set up fixed-size arrays within a struct. While you might not frequently declare inline arrays, you'll encounter them seamlessly as either System.Span<T>
or System.ReadOnlySpan<T>
when working with runtime APIs, for example.
Starting with C# 12, you can declare inline arrays as a struct type. According to the official language reference documentation:
An inline array is a structure that contains a contiguous block of N elements of the same type. It's a safe-code equivalent of the fixed buffer declaration available only in unsafe code. [..] Inline arrays are an advanced language feature, intended for high-performance scenarios where an inline, contiguous block of elements is faster than other alternative data structures.
A struct equipped with an inline buffer should offer performance akin to an unsafe fixed-size buffer. Also, an inline array doesn’t have a specific layout, except that it contains only a single field. They are defined as annotated structs, functioning much like standard arrays:
[System.Runtime.CompilerServices.InlineArray(10)]
public struct CharBuffer
{
private char _firstElement;
}
Source: Microsoft
The compiler validates the System.Runtime.CompilerServices.InlineArrayAttribute
attribute as follows: its length must be greater than zero, and its target type must be a struct.
In most cases, an inline array can be accessed like an array, both to read and write values. In addition, you can use the range
and index
operators. As for the type of the structure’s single field, the restrictions are minimal: it can't be a pointer type. You can find more about inline arrays in its feature speclet.
Interceptors are an experimental compiler feature available only in preview mode. Being an experimental feature means that it is subject to change or even removal in the near future. In a nutshell, an interceptor is a method that, during compile time, can seamlessly replace a call intended for an interceptable method with a call to itself. It achieves this by designating the original call locations it intends to replace. Essentially, interceptors offer a mechanism to alter the behavior of pre-existing code by introducing new code during compilation, often through a source generator.
When using an interceptor within a source generator, the goal is to modify existing code instead of merely adding to it. In this process, the source generator will replace calls targeting an interceptable method with those directed at the interceptor method. The interceptor feature specification provides a detailed design of the new feature, including code samples and usage restrictions. In order to use this new feature in your C# project, you must explicitly set the <Features>InterceptorsPreview</Features>
element in your project file.
In addition to these, other C# 12 features are already available for developers. Primary constructors, introduced in C# 9, are no longer restricted to record
types. Since Visual Studio 17.6 preview 2, they can now be created in any class
and struct
, which means it is possible to add parameters to the class or struct declaration and use these values inside the type body.
Other available C# 12 features are the possibility of adding optional parameters to lambda expressions and using the using
alias directive to alias any sort of type (not just named types). This allows you to create semantic aliases for tuple types, array types, pointer types, or any other unsafe types.
You can find more about the available C# 12 features on the official language documentation page. You can get C# 12 by installing the latest Visual Studio preview (Windows) or the latest version of the .NET 8 SDK (Windows, macOS, and Linux). You will also need to set the language version of your project to preview
:
<PropertyGroup>
<LangVersion>preview</LangVersion>
</PropertyGroup>