What's new in .NET 10?

The wait is over! .NET 10 is on the horizon, and it's time to celebrate the platform's anniversary. In this article, we'll dive into the latest enhancements, including JIT improvements, standard library extensions, and new SDK features.

Image

.NET 10 is a Long-Term Support (LTS) release, guaranteeing three years of support. This version doubles down on performance and security, with a special focus on cryptography. While we can't cover every single update, this article will highlight the most impactful changes across the libraries, runtime, and SDK.

What's New in C# 14

C# 14 introduces several exciting features, including extension blocks, the field keyword, and pattern-matching enhancements. A standout addition is the ability to use the null-conditional operator (?) for assignments.

Before C# 14, you had to write a null check to safely assign a property value:

if (user is not null)
{
    user.LastActive = DateTime.UtcNow;
}

Now, you can achieve the same result with a single, more expressive line:

user?.LastActive = DateTime.UtcNow;

This new syntax helps reduce boilerplate code, which is always a welcome improvement.

Performance Enhancements

As with every release, .NET 10 brings significant performance boosts. Key areas that have been optimized include LINQ, regular expressions, cryptography, JIT, AOT, and I/O operations. For a deep dive, be sure to check out the detailed post by Stephen Toub.

Library Updates

Cryptography

The System.Security.Cryptography library has been updated with support for three new post-quantum asymmetric algorithms:

  • ML-KEM (FIPS 203)
  • ML-DSA (FIPS 204)
  • SLH-DSA (FIPS 205)
As .NET 10 is an LTS release, adding post-quantum cryptography is a crucial, forward-thinking move. It helps defend against "harvest now, decrypt later" attacks, where adversaries store encrypted data today to decrypt it with future quantum computers.

Collections

The OrderedDictionary<TKey, TValue> type now includes new overloads for its TryAdd and TryGetValue methods. These new versions return the item's index as an out parameter, providing more contextual information.

Serialization

  • You can now configure how circular references are handled during serialization by specifying the ReferenceHandler in JsonSourceGenerationOptionsAttribute.
  • A new JsonSerializerOptions.AllowDuplicateProperties setting has been introduced to control whether to allow or disallow duplicate JSON properties during deserialization.

String Handling

  • Normalization: New APIs extend normalization beyond just strings, allowing you to work directly with char arrays and spans without first converting them to strings.
  • UTF-8 to Hex Conversion: New methods convert between UTF-8 byte sequences and hexadecimal representations without allocating intermediate strings, offering better performance.
  • Numeric Ordering: A new NumericOrdering option enables numerical string comparison instead of lexicographical. For example, with this option, 2 is treated as equal to 02.

Runtime and JIT Enhancements

AVX10.2 Support

.NET 10 introduces support for AVX10.2 instructions on x64 processors. While hardware supporting this instruction set is expected next year, this update ensures the runtime is ready to take full advantage of it as soon as it's available.

Stack Allocation for Small Arrays

.NET 10 now enables stack allocation for small arrays of both value and reference types. When the JIT compiler can determine that an array's lifetime is confined to the current method's scope, it will allocate it on the stack instead of the heap. This reduces pressure on the garbage collector (GC) and paves the way for further optimizations.

static void Sum()
{
    int[] numbers = {1, 2, 3};
    int sum = 0;

    for (int i = 0; i < numbers.Length; i++)
    {
        sum += numbers[i];
    }

    Console.WriteLine(sum);
}

Here, the numbers array will be allocated on the stack because its scope is limited to the Sum method. The same principle applies to arrays of reference types.

static void Print()
{
    string[] words = {Hello, World!};
    foreach (var str in words)
    {
        Console.WriteLine(str);
    }
}

Garbage Collector Write-Barrier Elision

The .NET garbage collector is generational, and a challenge arises when an object in an older generation holds a reference to an object in a younger one. To manage this, the GC uses a 'write barrier' to track these cross-generational references, but they come with a performance cost.

For the compiler, the best write barrier is no write barrier at all.

.NET 10 introduces optimizations that allow the JIT to eliminate unnecessary write barriers in certain scenarios, resulting in better overall performance.

SDK Updates

Cleaning Up Package References

Starting with .NET 10, the NuGet audit feature can now automatically identify and remove unused package references. This optimization reduces the number of packages restored and analyzed during the build process, speeding up development. This feature is enabled by default for all projects targeting .NET 10 or newer.

Unified MSBuild

Previously, MSBuild tasks running in Visual Studio used the .NET Framework, while those in the dotnet CLI used modern .NET, forcing developers to maintain two versions. With .NET 10, both Visual Studio and msbuild.exe will run MSBuild tasks built for .NET, unifying the ecosystem and eliminating duplicate work.

New CLI Commands

  • dotnet tool exec: Run a .NET tool without installing it globally or locally, which is especially useful for CI/CD pipelines.
  • dnx script: A new shorthand for executing tools that forwards all arguments directly to the dotnet CLI.
  • --cli-schema: Inspect the CLI's command structure with this parameter, which outputs a JSON tree of available commands and subcommands.

Project-Free C# File Execution

You can now build and run single C# files directly without creating a project file, simplifying the process for small utilities, prototypes, and experiments. Just use the dotnet run command on any .cs file. These single-file applications default to Native AOT compilation and can be published as self-contained native executables with dotnet publish.

Conclusion

.NET 10 is a robust release, a fitting tribute for its anniversary and a worthy Long-Term Support version. The consistent focus on performance and modernization is commendable. This article has touched on just a few highlights. For a complete list of changes, check out the official documentation. What are your favorite features? Share your thoughts in the comments below!