NDepend Blog

Improve your .NET code quality with NDepend

.NET 8 Top 10 New Features

April 24, 2024 7 minutes read

.NET 8 has been officially released in November 2023. You can download it here. Designated as an LTS (Long Term Support) version, it guarantees ongoing support, updates, and bug fixes for a minimum of three years from its launch. This commitment empowers developers to embrace this new version with confidence. .NET 8 will become the default version for many organizations over the next years.

Building on the changes introduced in .NET 7, this release adds further enhancements. Let’s dive into the .NET 8 Top 10 New Features:

Performances, Performances, Performances

Microsoft once again has committed a substantial amount of resources to enhance the performance of its new .NET 8. As usual, Stephen Toub has compiled an exhaustive, hundreds-of-pages-long article summarizing all these improvements: Performance Improvements in .NET 8.

Here are three key performance improvements that stand out to me:

  • The method List<T>.AddRange(IEnumerable<T>) has been rewritten to achieve better performance when the sequence is not a ICollection<T>.
Method Job Mean Ratio
AddRange .NET 7 6.365 us 1.00
AddRange .NET 8 w/o PGO 4.396 us 0.69
AddRange .NET 8 2.445 us 0.38
  • Int32.ToString() performance has been improved by caching string values from 0 to 299. Also, .NET engineers have cut the number of divisions in half. This reduction results from dividing by 100 to obtain two digits, as opposed to dividing by 10 to obtain a single digit.
Method Runtime i Mean Ratio Allocated Alloc Ratio
Int32ToString .NET 7.0 12 16.253 ns 1.00 32 B 1.00
Int32ToString .NET 8.0 12 1.985 ns 0.12 0.00
Int32ToString .NET 7.0 1234567890 26.964 ns 1.00 48 B 1.00
Int32ToString .NET 8.0 1234567890 17.082 ns 0.63 48 B 1.00
  • On Mac OS, File.Copy() has significantly improved its speed by relying on the OS’s clonefile function, if it is available, for the copying process.
Method Runtime Mean Ratio
FileCopy .NET 7.0 1,624.8 us 1.00
FileCopy .NET 8.0 366.7 us 0.23

New .NET 8 Garbage Collection DATAS Feature (Dynamic Adaptation TApplication Sizes)

The .NET 8 GC introduces DATAS (Dynamic Adaptation To Application Sizes). It adjusts the application’s memory usage based on Live Data Size (LDS), which includes long-lived data and inflight data during a GC event. DATAS has two main use cases:

  1. It’s beneficial for bursty workloads in memory-constrained environments, like containerized applications with memory limits. DATAS shrinks or expands the heap size as needed.
  2. It’s useful for small workloads using Server GC, ensuring the heap size aligns with the application’s actual requirements.

While some initially called it “the Dynamic GC” DATAS’ key focus is on adapting to your application’s size. GC has always been dynamic, but DATAS fine-tunes it to better suit the workloads in .NET.

Explore an in-depth article on DATAS authored by the renowned .NET GC expert, Stephens Maoni, by clicking here: Dynamically Adapting To Application Sizes

System.Text.Json Serialization and Deserialization

In .NET 8, System.Text.Json brings an array of thrilling updates for developers.  This release elevates the user experience in Native AOT (Ahead-Of-Time) applications thanks to many improvements on the source generator including:

  1. Supports serializing types with requiredand init properties.
  2. JsonSourceGenerationOptionsAttribute: Aligns with JsonSerializerOptions, enabling compile-time serialization configuration.
  3. Improved Type Handling: Ignores inaccessible properties, allows nesting JsonSerializerContext declarations, and handles compiler-generated types dynamically.
  4. JsonStringEnumConverter<TEnum>: A new converter type simplifies enum serialization in Native AOT applications.
  5. Additionally, the JsonConverter.Type property helps retrieve the type of a non-generic JsonConverter instance, with nullable support for various scenarios.

Many other enhancements are packed including:

  • JsonNamingPolicy now incorporates new naming policies for converting property names to snake_case (with underscores) and  kebab-case (with hyphens).
  • You can now deserialize data onto read-only fields or read-only properties, which are those without a set accessor.
  • You can now opt to disable the reflection-based serializer as the default option. This capability is valuable for preventing the unintended inclusion of reflection components, particularly in trimmed and Native AOT applications.

More information about System.Text.Json improvements can be found in this official post: What’s new in System.Text.Json in .NET 8

Convenient New APIs for Managing Randomness

.NET 8 unveils game-changing methods to improve our approach to randomness. This is especially useful for machine learning applications. For example the new methods System.Random.GetItems() and System.Security.Cryptography.RandomNumberGenerator.GetItems() enable you to select a specified number of items randomly from an input set:
net8.0 randomness
The new Random.Shuffle and RandomNumberGenerator.Shuffle<T>(Span<T>) methods let’s randomize the order of a span. These methods are valuable for mitigating training bias in machine learning, (so the first item isn’t necessarily training, and the last item isn’t necessarily test).
net8.0 shuffle

New Time Abstraction API

The newly introduced TimeProvider class and ITimer interface offer time abstraction functionality, facilitating the simulation of time in testing scenarios. The TimeProvider is an abstract class featuring numerous virtual functions, which makes it an ideal candidate for integration with mocking frameworks. This allows for seamless and comprehensive mocking of all its aspects. For example:


Let’s underline this remark from a Microsoft engineer:

“At the end of the day, we expect almost no one will use anything other than TimeProvider.System in production usage. Unlike many abstractions then, this one is special: it exists purely for testability”.

Notice that you can also harness time abstraction to simulate Task operations that depend on time progression, such as Task.Delay() and Task.WaitAsync().

These time abstractions were highly anticipated, following years of debates and discussions.

New Types that can Improve Performance in Various Situations

  • .NET 8 offers the new System.Collections.Frozen namespace. It contains the new collection classes FrozenSet<T> and FrozenDictionary<TKey,TValue>. The Frozen qualifier means that the collections are immutable: it cannot be changed once created. Internally the implementation does harness this requirement to allows for faster enumeration and faster lookup operations like Contains() or TryGetValue(). These new frozen collections prove particularly valuable in scenarios where collections are initially populated and subsequently endure for the entire lifecycle of a long-lived application.

  • The new class System.Buffers.SearchValues<T> is optimized for scenarios where a consistent set of values is frequently employed for runtime searches like for example in the implementation of String.IndexOfAny(char[]). When you create a SearchValues<T>instance, all the essential data required to optimize future searches is computed in advance, streamlining the process.
  • The new class System.Text.CompositeFormat proves invaluable for optimizing format strings -like "First Name:{0} Last Name: {1}"– not known at compile time. While there is an initial overhead in tasks such as string parsing, this proactive approach significantly reduces the computational burden in subsequent uses, enhancing performance and efficiency.

UTF8 Formatting

To enable the generation of a string-like representation of your type into a destination span, implement the recently introduced IUtf8SpanFormattable interface for your type:

This interface is similar to ISpanFormattable. It is designed specifically for UTF-8 and Span<byte>, as opposed to UTF-16 and Span<char>.

In .NET 8 all primitive types (and more) implement this interface: ByteComplexCharDateOnlyDateTimeDateTimeOffsetDecimalDoubleGuidHalfIPAddressIPNetworkInt16Int32Int64Int128IntPtrNFloatSByteSingleRuneTimeOnlyTimeSpanUInt16UInt32UInt64UInt128UIntPtr, and Version.

Stream-based ZipFile methods

It is now feasible to compress files from a directory using a stream without the need to cache them in a temporary file. This allows for direct management of the compression result in memory. These new APIs prove beneficial in scenarios where disk space is limited, as they eliminate the need to utilize the disk as an intermediate step. Here are the new APIs:

Support for the Intel AVX-512 instruction set

.NET Core 3.0 proposed support for SIMD by incorporating platform-specific hardware intrinsics APIs for x86/x64. Subsequently, .NET 5 extended this support to Arm64, and with the advent of .NET 7, cross-platform hardware intrinsics were introduced. .NET 8 further enhances SIMD capabilities by introducing Vector512<T> and extending support for Intel Advanced Vector Extensions 512 (AVX-512) instructions.

In particular, .NET 8 introduces support for the following key AVX-512 features:

  1. 512-bit vector operations.
  2. An additional 16 SIMD registers.
  3. Additional instructions are available for 128-bit, 256-bit, and 512-bit vectors.

Moreover, even without explicitly utilizing Vector512-specific or Avx512F-specific instructions in your code, you are likely to benefit from the improved AVX-512 support. The JIT compiler can leverage the extra registers and instructions implicitly when you use Vector128<T> or Vector256<T>.

Finally, note that if you have AVX-512 compatible hardware, Vector512.IsHardwareAccelerated will now return true.

Cryptography

.NET 8 now proposes support for SHA-3 hashing primitives. SHA-3 is currently compatible with Linux running OpenSSL 1.1.1 or later, and Windows 11 Build 25324 or later. Existing APIs offering SHA-2 now include their SHA-3 counterparts encompassing  SHA3_256SHA3_384, and SHA3_512 for hashing; HashAlgorithmName.SHA3_256HashAlgorithmName.SHA3_384, and HashAlgorithmName.SHA3_512 for hashing where the algorithm is configurable; HMACSHA3_256HMACSHA3_384, and HMACSHA3_512 for HMAC;  and RSAEncryptionPadding.OaepSHA3_256RSAEncryptionPadding.OaepSHA3_384, and RSAEncryptionPadding.OaepSHA3_512 for RSA OAEP encryption.

Conclusion

Summing it up, .NET 8 stands as a substantial leap forward, introducing a plethora of new features and enhancements. The new APIs and capabilities are well-suited to ensure the competitiveness and security of your code over the next three years.

.NET 8 is released along with C# 12. This new C# version introduces interesting new syntaxes explained in this post: Unveiling the Impressive Features of Upcoming C# 12

Comments:

  1. architects bangalore says:

    “This is an excellent contribution to the conversation. Your thoughtful analysis and practical advice make it a valuable resource. Keep up the fantastic work!”

Leave a Reply

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