Sustainable Code with .NET 9

Sustainable Code is a constantly growing GitHub repository created by me , in which I collect various everyday code snippets and measure the performance of the different implementation ways.
The goal is to create a collection of code that virtually everyone has in front of them every day and can thus easily implement the best way for themselves and their use case.

I took the current release of .NET 9 as an opportunity to update all the examples accordingly and compare them between .NET 7, .NET 8 and - if the dependencies have already been updated - .NET 9.

Here are my rough findings of some of the comparison snippets.

Condition vs Exception ðŸ"Š

The goal here is to show why exceptions are not a suitable way to control application logic - and that it is advisable to avoid exceptions as much as possible, as recommended by the C# Coding Guidelines .

 1BenchmarkDotNet v0.14.0, Windows 10 (10.0.19045.5131/22H2/2022Update)
 2AMD Ryzen 9 9950X, 1 CPU, 32 logical and 16 physical cores
 3.NET SDK 9.0.100
 4  [Host]   : .NET 9.0.0 (9.0.24.52809), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
 5  .NET 7.0 : .NET 7.0.20 (7.0.2024.26716), X64 RyuJIT AVX2
 6  .NET 8.0 : .NET 8.0.11 (8.0.1124.51707), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
 7  .NET 9.0 : .NET 9.0.0 (9.0.24.52809), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
 8
 9
10| Method    | Runtime  | Mean         | Error     | StdDev    | Ratio    | RatioSD | Gen0   | Allocated |
11|---------- |--------- |-------------:|----------:|----------:|---------:|--------:|-------:|----------:|
12| Condition | .NET 7.0 |    11.495 ns | 0.0733 ns | 0.0612 ns |    10.30 |    0.06 |      - |         - |
13| Condition | .NET 8.0 |     1.299 ns | 0.0041 ns | 0.0034 ns |     1.16 |    0.00 |      - |         - |
14| Condition | .NET 9.0 |     1.116 ns | 0.0035 ns | 0.0031 ns |     1.00 |    0.00 |      - |         - |
15| Exception | .NET 7.0 | 2,336.653 ns | 9.1249 ns | 8.5355 ns | 2,092.87 |    9.28 | 0.0114 |     232 B |
16| Exception | .NET 8.0 | 2,303.988 ns | 2.6537 ns | 2.0719 ns | 2,063.61 |    5.80 | 0.0114 |     232 B |
17| Exception | .NET 9.0 | 1,072.247 ns | 8.2707 ns | 7.3317 ns |   960.38 |    6.84 | 0.0134 |     224 B |

We can see here that exceptions have become significantly more efficient with .NET 9 - but we are still talking about thousand times slower behavior compared to a condition.

Full sample here .

Any vs Count > 0 ðŸ"Š

This example is about showing how Count vs. Any() works in terms of performance.

 1BenchmarkDotNet v0.14.0, Windows 10 (10.0.19045.5131/22H2/2022Update)
 2AMD Ryzen 9 9950X, 1 CPU, 32 logical and 16 physical cores
 3.NET SDK 9.0.100
 4  [Host]   : .NET 9.0.0 (9.0.24.52809), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
 5  .NET 7.0 : .NET 7.0.20 (7.0.2024.26716), X64 RyuJIT AVX2
 6  .NET 8.0 : .NET 8.0.11 (8.0.1124.51707), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
 7  .NET 9.0 : .NET 9.0.0 (9.0.24.52809), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
 8
 9
10| Method | Runtime  | Items | Mean      | StdDev    | Ratio | RatioSD |
11|------- |--------- |------ |----------:|----------:|------:|--------:|
12| Any    | .NET 7.0 | 0     | 1.9150 ns | 0.0271 ns | 4.069 |    0.06 |
13| Any    | .NET 8.0 | 0     | 1.8727 ns | 0.0139 ns | 3.979 |    0.04 |
14| Any    | .NET 9.0 | 0     | 0.4706 ns | 0.0031 ns | 1.000 |    0.01 |
15|        |          |       |           |           |       |         |
16| Count  | .NET 7.0 | 0     | 0.0034 ns | 0.0017 ns | 0.007 |    0.00 |
17| Count  | .NET 8.0 | 0     | 0.0038 ns | 0.0018 ns | 0.008 |    0.00 |
18| Count  | .NET 9.0 | 0     | 0.0161 ns | 0.0019 ns | 0.034 |    0.00 |
19|        |          |       |           |           |       |         |
20| Any    | .NET 7.0 | 1     | 1.9256 ns | 0.0194 ns |  4.06 |    0.05 |
21| Any    | .NET 8.0 | 1     | 1.8670 ns | 0.0057 ns |  3.94 |    0.02 |
22| Any    | .NET 9.0 | 1     | 0.4740 ns | 0.0027 ns |  1.00 |    0.01 |
23|        |          |       |           |           |       |         |
24| Count  | .NET 7.0 | 1     | 0.0082 ns | 0.0029 ns |  0.02 |    0.01 |
25| Count  | .NET 8.0 | 1     | 0.0062 ns | 0.0013 ns |  0.01 |    0.00 |
26| Count  | .NET 9.0 | 1     | 0.0189 ns | 0.0051 ns |  0.04 |    0.01 |
27|        |          |       |           |           |       |         |
28| Any    | .NET 7.0 | 10    | 1.9292 ns | 0.0199 ns |  4.09 |    0.04 |
29| Any    | .NET 8.0 | 10    | 1.8612 ns | 0.0050 ns |  3.95 |    0.02 |
30| Any    | .NET 9.0 | 10    | 0.4717 ns | 0.0015 ns |  1.00 |    0.00 |
31|        |          |       |           |           |       |         |
32| Count  | .NET 7.0 | 10    | 0.0107 ns | 0.0051 ns |  0.02 |    0.01 |
33| Count  | .NET 8.0 | 10    | 0.0056 ns | 0.0035 ns |  0.01 |    0.01 |
34| Count  | .NET 9.0 | 10    | 0.0159 ns | 0.0026 ns |  0.03 |    0.01 |
35|        |          |       |           |           |       |         |
36| Any    | .NET 8.0 | 100   | 1.8619 ns | 0.0126 ns |  3.93 |    0.05 |
37| Any    | .NET 7.0 | 100   | 1.9241 ns | 0.0252 ns |  4.06 |    0.07 |
38| Any    | .NET 9.0 | 100   | 0.4740 ns | 0.0055 ns |  1.00 |    0.02 |
39|        |          |       |           |           |       |         |
40| Count  | .NET 7.0 | 100   | 0.0102 ns | 0.0029 ns |  0.02 |    0.01 |
41| Count  | .NET 8.0 | 100   | 0.0058 ns | 0.0071 ns |  0.01 |    0.01 |
42| Count  | .NET 9.0 | 100   | 0.0157 ns | 0.0026 ns |  0.03 |    0.01 |

Count is still the much faster variant, but with .NET 9 there was a real performance boost for Linq.

Full sample here .

Small Hotpath Methods ðŸ"Š

In the hotpath comparison - I am a fan of local methods and their better readability and performance benefit - there was no relevant improvement with .NET 9.

 1BenchmarkDotNet v0.14.0, Windows 10 (10.0.19045.5131/22H2/2022Update)
 2AMD Ryzen 9 9950X, 1 CPU, 32 logical and 16 physical cores
 3.NET SDK 9.0.100
 4  [Host]   : .NET 9.0.0 (9.0.24.52809), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
 5  .NET 7.0 : .NET 7.0.20 (7.0.2024.26716), X64 RyuJIT AVX2
 6  .NET 8.0 : .NET 8.0.11 (8.0.1124.51707), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
 7  .NET 9.0 : .NET 9.0.0 (9.0.24.52809), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
 8
 9
10| Method       | Runtime  | Iterations | Mean         | Error      | StdDev     | Ratio |
11|------------- |--------- |----------- |-------------:|-----------:|-----------:|------:|
12| WithoutLocal | .NET 7.0 | 10         |    11.076 ns |  0.1264 ns |  0.1121 ns |  3.94 |
13| WithoutLocal | .NET 8.0 | 10         |     2.791 ns |  0.0315 ns |  0.0295 ns |  0.99 |
14| WithoutLocal | .NET 9.0 | 10         |     2.812 ns |  0.0181 ns |  0.0151 ns |  1.00 |
15|              |          |            |              |            |            |       |
16| WithLocal    | .NET 7.0 | 10         |     3.494 ns |  0.0859 ns |  0.0990 ns |  1.24 |
17| WithLocal    | .NET 8.0 | 10         |     2.807 ns |  0.0147 ns |  0.0130 ns |  0.99 |
18| WithLocal    | .NET 9.0 | 10         |     2.827 ns |  0.0277 ns |  0.0246 ns |  1.00 |
19|              |          |            |              |            |            |       |
20| WithoutLocal | .NET 7.0 | 100        |   119.236 ns |  1.5937 ns |  1.4907 ns |  4.91 |
21| WithoutLocal | .NET 8.0 | 100        |    25.734 ns |  0.1918 ns |  0.1794 ns |  1.06 |
22| WithoutLocal | .NET 9.0 | 100        |    24.262 ns |  0.2096 ns |  0.1960 ns |  1.00 |
23|              |          |            |              |            |            |       |
24| WithLocal    | .NET 7.0 | 100        |    40.118 ns |  0.8185 ns |  0.8758 ns |  1.64 |
25| WithLocal    | .NET 8.0 | 100        |    25.077 ns |  0.3515 ns |  0.3288 ns |  1.03 |
26| WithLocal    | .NET 9.0 | 100        |    24.466 ns |  0.2786 ns |  0.2606 ns |  1.00 |
27|              |          |            |              |            |            |       |
28| WithoutLocal | .NET 7.0 | 1000       | 1,135.122 ns | 17.3263 ns | 16.2071 ns |  4.74 |
29| WithoutLocal | .NET 8.0 | 1000       |   250.022 ns |  1.5989 ns |  1.4174 ns |  1.04 |
30| WithoutLocal | .NET 9.0 | 1000       |   239.307 ns |  1.5506 ns |  1.4504 ns |  1.00 |
31|              |          |            |              |            |            |       |
32| WithLocal    | .NET 7.0 | 1000       |   330.232 ns |  5.3309 ns |  4.9866 ns |  1.37 |
33| WithLocal    | .NET 8.0 | 1000       |   241.045 ns |  2.0723 ns |  1.9384 ns |  1.00 |
34| WithLocal    | .NET 9.0 | 1000       |   241.217 ns |  1.8586 ns |  1.6476 ns |  1.00 |

Full sample here .

Source Generator based Logging Messages ðŸ"Š

Logging is expensive, so it is advisable to use compile-time logging through Source Code Generators .

 1BenchmarkDotNet v0.14.0, Windows 10 (10.0.19045.5131/22H2/2022Update)
 2AMD Ryzen 9 9950X, 1 CPU, 32 logical and 16 physical cores
 3.NET SDK 9.0.100
 4  [Host]   : .NET 9.0.0 (9.0.24.52809), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
 5  .NET 7.0 : .NET 7.0.20 (7.0.2024.26716), X64 RyuJIT AVX2
 6  .NET 8.0 : .NET 8.0.11 (8.0.1124.51707), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
 7  .NET 9.0 : .NET 9.0.0 (9.0.24.52809), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
 8
 9
10| Method              | Runtime  | Mean      | Error    | StdDev   | Ratio | RatioSD | Gen0   | Allocated |
11|-------------------- |--------- |----------:|---------:|---------:|------:|--------:|-------:|----------:|
12| SourceCodeGenerated | .NET 7.0 |  83.49 ns | 0.299 ns | 0.279 ns |  1.24 |    0.01 |      - |         - |
13| SourceCodeGenerated | .NET 8.0 |  82.12 ns | 0.252 ns | 0.224 ns |  1.22 |    0.01 |      - |         - |
14| SourceCodeGenerated | .NET 9.0 |  67.30 ns | 0.365 ns | 0.341 ns |  1.00 |    0.01 |      - |         - |
15|                     |          |           |          |          |       |         |        |           |
16| Concat              | .NET 7.0 | 112.57 ns | 0.235 ns | 0.208 ns |  1.67 |    0.01 | 0.0286 |     480 B |
17| Concat              | .NET 8.0 |  96.94 ns | 1.239 ns | 1.098 ns |  1.44 |    0.02 | 0.0286 |     480 B |
18| Concat              | .NET 9.0 |  94.59 ns | 1.136 ns | 1.007 ns |  1.41 |    0.02 | 0.0286 |     480 B |
19|                     |          |           |          |          |       |         |        |           |
20| Interpolation       | .NET 7.0 | 112.79 ns | 0.444 ns | 0.416 ns |  1.68 |    0.01 | 0.0286 |     480 B |
21| Interpolation       | .NET 8.0 |  97.08 ns | 1.208 ns | 1.071 ns |  1.44 |    0.02 | 0.0286 |     480 B |
22| Interpolation       | .NET 9.0 |  94.12 ns | 0.620 ns | 0.580 ns |  1.40 |    0.01 | 0.0286 |     480 B |

With .NET 9, this recommended variant has become even faster, making implementation all the more worthwhile, both in terms of memory allocation and performance.

Full sample here .

Summary

.NET 9 is another release that brings with it an enormous performance benefit and thus makes an entire software industry more efficient - for those who rely on .NET.


Let's Work Together

Looking for an experienced Platform Architect or Engineer for your next project? Whether it's cloud migration, platform modernization or building new solutions from scratch - I'm here to help you succeed.

New Platforms
Modernization
Training & Consulting

Comments

Twitter Facebook LinkedIn WhatsApp