What’s new in .NET 9?
.NET 9 has been released, so it’s time to start porting our projects to the new version! In this article, we’ll look at new features and enhancements: C# 13, performance, BuildCheck, GC, LINQ, NuGet Audit, and much more.
The .NET 9 update primarily focuses on cloud apps and performance enhancements. This is a standard-term support (STS) release that will be maintained for 18 months.
This article will mostly cover the most buzzworthy features in the libraries, Runtime, and SDK. It’s tough to cover everything that’s new in ASP.NET Core, .NET MAUI, .NET Aspire, Entity Framework Core, and WPF in a single article.
C# 13
We’ve already explored all new C# 13 features in a separate article, where we’ve discussed partial properties and indexers, params collections, the new Lock class, object initialization using the “from the end” index, and much more. It’s a joy to see that C# 13 brings more updates this year than last year. However, not all of them are really handy. What do you think of the update? Our team instantly came up with some fresh ideas for enhancing the C# analyzer rules.
Just like we always do, we’re adding support for the latest .NET and C# versions. We’ll introduce them in PVS-Studio 7.34, scheduled for early December. Subscribe to the PVS-Studio newsletter to stay up to date!
Performance
Stephen Toub publishes a MASSIVE article with each new .NET release, outlining new performance-wise improvements. As usual, this release is no exception. The author describes new improvements across various areas of .NET and includes some benchmarks. Indeed, developers have refined the JIT, GC, Native AOT, various data types, reflection, LINQ, and a dozen other things.
I’d recommend reading this article to keep up with the latest updates.
Libraries
LINQ
In .NET 9, the CountBy, AggregateBy, and Index methods have been added to System.Linq.
New OrderedDictionary<TKey, TValue> type
.NET 9 has introduced a new generic type, OrderedDictionary<TKey, TValue>. This is a more flexible analog of the common OrderedDictionary, which has keys and values represented by the object type.
New ReadOnlySet<T> type
Sometimes we need to pass a read-only collection. We use ReadOnlyCollection<T> for IList<T>. If we needed to pass the immutable equivalent of IDictionary<TKey, TValue>, we’d used ReadOnlyDictionary<TKey, TValue>. However, there was no alternative to ISet<T>. .NET 9 has fixed it and introduced ReadOnlySet<T>.
New Tensor<T> type
Tensors are a key part of AI development, and .NET 9 has introduced a new type to facilitate seamless integration into AI libraries such as ML.NET, TorchSharp, and ONNX Runtime.
allows ref struct in libraries
C# 13 has added a handy feature allowing the compiler and runtime to use ref struct for generic parameters. In .NET 9, developers can use the allows ref struct in the various places of the library.
[GeneratedRegex] for properties
.NET 7 introduced the GeneratedRegex source generator to generate regular expressions. It spots the [GeneratedRegex] attribute on a partial method that returns Regex and then auto-generates a method implementation that contains the operation logic. In .NET 9, thanks to the introduction of the partial properties in C# 13, now we can use the [GeneratedRegex] attribute on these properties.
For example:
[GeneratedRegex("\b\w{5}\b")]
private static partial Regex FiveCharWord();
SDK
Terminal Logger is default
Terminal Logger now always runs by default. This logging feature has been introduced in .NET 8. Previously, we had to manually enable Terminal Logger via \tl. Now, it’s enabled by default.
Parallel test running
Now dotnet test enables us to run tests in parallel across various target frameworks for the same project. This is compatible with the new Terminal Logger.
NuGet Audit
In .NET 8, when we used a dotnet restore, the packages were checked for known vulnerabilities. .NET 9 has modified the default audit mode. Now both direct and transitive dependencies are checked for vulnerabilities.
Just a quick reminder about vulnerable packages: as mentioned in the previous article about .NET 8, PVS-Studio can detect known vulnerabilities in both direct and transitive dependencies. Moreover, PVS-Studio can search for potential vulnerabilities in your code. Get a trial license and try the analyzer on your code base.
BuildCheck
.NET 9 has received a new feature to protect against bugs during the build process. To run a new mode, use the /check flag. Now .NET 9 includes several checks — though the number of checks will increase over time. Plus, we can write our own rules to suit our needs.
Workload history
To streamline tracking workload changes, .NET 9 SDK has introduced a new dotnet workload history command to review changes and rollback them to the previous version.
Runtime
Feature switch
Now the .NET 9 runtime has two new attributes to toggle areas of functionality:
They help keep the application size smaller. If we release a trimmed application or compile with Native AOT, any code marked with new attributes will be removed based on the build settings.
Dynamic Adaptation To Application Sizes (DATAS)
Dynamic Adaptation to Application Size (DATAS), introduced in .NET 8, is now enabled by default. DATAS adjusts the GC heap size depending on the application load.
JIT compilation enhancement
.NET 9 has brought tons of JIT-related enhancements, including better loop optimization, refined PGO, enhanced embedded methods, and more. It’d be incredibly challenging to list and explain all of these improvements here, those interested in the JIT-related improvements can check out the full list of updates.
Register Allocator improvements
In .NET 9, RyuJIT, Just-In-Time compiler in .NET, uses a faster and simpler approach for register allocation when compiling unoptimized code. RyuJIT can cut runtime by 10% in certain scenarios.
Conclusion
This year, many features have been put into practice, tested, enhanced, and enabled by default. While there aren’t a lot of new features, they’re going to make a noticeable impact. Often, the most valuable updates are the ones that work behind the scenes, even if developers don’t always notice them directly.
As I said before, this article highlights only the coolest updates that the majority of devs will find useful. You can find the full list of features here. If I’ve any noteworthy feature, please share them in the comments.
That’s it. Now we set the alarm for one year and wait for the next .NET 10 release — it’ll be a milestone anniversary :) As we look forward to .NET 10, tell us what features are you hoping to see?