Exploring Performance with New Collection Expression Syntax in C# 12
C# 12 introduces a new way to initialize collections, known as the collection expression syntax. This feature not only simplifies code but also enhances performance, especially for large collections.
IDE0305: Use collection expression for fluent - .NET
Old Syntax
New Syntax
A Comparative Analysis
1. Small Collections
Traditional Syntax
Compiles to
New C# 12 Syntax
Compiles to
Benchmark Result:
Method | Mean | Allocated |
|---|---|---|
Traditional Syntax | 20.17 ns | 72 B |
New C# 12 Syntax | 17.26 ns | 72 B |
Traditional Syntax: 20.17 ns
New Syntax: 17.26 ns
The new syntax shows a ~17% performance improvement, which can be significant in performance-critical applications.
2. Large Collections
For larger collections, the performance difference becomes more pronounced.
Traditional Syntax (Loop-Based)
Compiles to
New C# 12 Syntax
Compiles to
Benchmark Result:
Method | Mean | Allocated |
|---|---|---|
Traditional Syntax | 572.2 us | 1024.48 KB |
New C# 12 Syntax | 127.6 us | 390.72 KB |
Traditional Syntax: 572.2 us
New Syntax: 127.6 us
In this scenario, the new syntax is more than 77% or 4 times faster than the traditional approach. Additionally, there's a significant reduction in memory allocation (about 63% less), which is crucial for large-scale applications.
Understanding CollectionsMarshal and Span<T>
CollectionsMarshal: This class in .NET provides low-level utilities for collections. In the new syntax,CollectionsMarshal.SetCountefficiently sets the number of elements in the list, potentially reducing the overhead of multiple memory allocations that might occur with repeatedAddcalls if the list needs resizing.Span<T>: TheSpan<T>struct is a versatile façade over arrays, strings, or any contiguous memory block. It's primarily designed for micro-optimization, particularly in writing code that minimizes managed memory allocations, thus easing the burden on the garbage collector. (CollectionsMarshal.AsSpanprovides access to a list's internal buffer as aSpan<T>). This allows the compiler to generate code that directly writes data into the list's memory block, bypassing the overhead of theAddmethod for each element. Additionally,Span<T>facilitates slicing, which allows working with parts of an array or string efficiently, without the need for creating copies of these segments. ( C# 10 in a Nutshell Ch 23)
Conclusion
The new collection expression syntax in C# 12 offers a significant performance boost, particularly with larger collections created from existing collections (using the spread .. operator). This feature enhances not just the speed but also the memory efficiency, making it a preferable choice in scenarios where performance is a key concern. While the benefit is less noticeable with small, literal collections, it becomes substantial with larger datasets, demonstrating the efficiency of modern C# capabilities in handling complex and large-scale data.
See Also:
Imperative vs Functional (Declarative, Expressive) Style of Programming (declarative style)
Memory Allocation and Management (mentions
Span<T>)Transitioning from Classes to Records and Adopting Immutable Collections in C# (collections focus)
Utilizing Record Structs for Enhanced Performance in .NET (performance focus)