Hello there

My current technology stack: .NET 9, Python, TypeScript, and Azure.

I develop microservices and terraform of different sizes. Sharing my challenges and key learning.

About

The views expressed in this blog are my own and do not reflect my employer's. I am not responsible for any consequences of using the information provided. This blog is for educational purposes only, not for commercial use. Readers should apply their own judgment.

String Concatenation Performance in .NET 9

July 31, 2024 Dipankar Haldar 47 people viewed this post

Introduction

String concatenation is a common operation in .NET applications, but choosing the right approach is crucial for performance and memory efficiency. In .NET 9, several optimizations have improved string handling, but the best approach still depends on the use case.

This article explores different ways to concatenate strings in .NET 9 and benchmarks their performance.


String Concatenation Methods in .NET 9

  • Using + (String Concatenation Operator)
  • Using String.Concat Method
  • Using StringBuilder
  • Using string.Join
  • Using Interpolation ($"...")
  • Using Span<char> for Memory Efficiency (Advanced)

Benchmarking String Concatenation Methods

public class StringConcatenationBenchmark
{
    private readonly string str1 = "Hello";
    private readonly string str2 = "World";
    private readonly string str3 = "!";
    
    public string ConcatenationOperator() => str1 + " " + str2 + str3;

    public string StringConcat() => string.Concat(str1, " ", str2, str3);

    public string StringJoin() => string.Join(" ", str1, str2) + str3;

    public string StringBuilderConcatenation()
    {
        var sb = new StringBuilder();
        sb.Append(str1).Append(" ").Append(str2).Append(str3);
        return sb.ToString();
    }

    public string StringInterpolation() => $"{str1} {str2}{str3}";

    public string SpanConcatenation()
    {
        Span<char> buffer = stackalloc char[20]; // Allocate stack memory
        str1.AsSpan().CopyTo(buffer);
        buffer[str1.Length] = ' ';
        str2.AsSpan().CopyTo(buffer.Slice(str1.Length + 1));
        buffer[str1.Length + 1 + str2.Length] = '!';
        return new string(buffer.Slice(0, str1.Length + 2 + str2.Length));
    }
}

Let's compare the performance of these methods using BenchmarkDotNet.

Test Environment:

  • Processor: 13th Gen Intel Core i7-1370P, 1 CPU, 20 logical and 14 physical cores
  • .NET SDK: 9.0.103
  • Runtime: .NET 9.0.2 (9.0.225.6610), X64 RyuJIT AVX2

Performance Results

Method Mean Error StdDev Median Gen0 Allocated
ConcatenationOperator 10.44 ns 0.207 ns 0.183 ns 10.48 ns 0.0038 48 B
StringConcat 13.39 ns 1.366 ns 4.027 ns 10.69 ns 0.0038 48 B
StringJoin 17.99 ns 0.509 ns 1.342 ns 17.45 ns 0.0076 96 B
StringBuilderConcatenation 18.89 ns 0.194 ns 0.190 ns 18.86 ns 0.0121 152 B
StringInterpolation 10.47 ns 0.136 ns 0.113 ns 10.48 ns 0.0038 48 B
SpanConcatenation 12.28 ns 0.094 ns 0.083 ns 12.29 ns 0.0038 48 B

Performance Insights

+ (Concatenation Operator)

✔️ Simple and readable, but creates intermediate string allocations.
✔️ Suitable for a small number of concatenations.

string.Concat

✔️ Slightly faster than + since it avoids unnecessary intermediate allocations.
✔️ Best for simple concatenations.

string.Join

✔️ Ideal when concatenating multiple strings with a separator.
✔️ Slightly higher memory usage.

StringBuilder

✔️ Most efficient for large, dynamic concatenations.
✔️ Reduces memory allocations compared to +.

String Interpolation ($"...")

✔️ Internally optimized, nearly as fast as +.
✔️ Suitable for improving readability.

Span<char> (stackalloc)

✔️ Fastest and most memory-efficient.
✔️ Best for low-level, performance-critical scenarios.


Best Practices for String Concatenation in .NET 9

  • For a few strings: Use + or string.Concat.
  • For multiple strings with separators: Use string.Join.
  • For dynamic or frequent concatenation: Use StringBuilder.
  • For high-performance scenarios: Use Span<char> (advanced use cases).

Conclusion

While .NET 9 brings optimizations, the best method depends on performance needs, readability, and memory efficiency.
StringBuilder remains the best choice for frequent concatenations.
Span<char> provides maximum efficiency for low-level optimizations.