From 88633ce738420340f2839d9b87f44f346b638fe4 Mon Sep 17 00:00:00 2001 From: prozolic <42107886+prozolic@users.noreply.github.com> Date: Wed, 8 Jul 2026 22:10:25 +0900 Subject: [PATCH 1/2] Add fast path in string.Concat This PR adds a fast path for string.Concat when the input value is List or string?[]. This fast path is based on the pattern already used in Join(string? separator, IEnumerable values). I have also added tests for the fast path and fallback path. --- src/libraries/Common/tests/Tests/System/StringTests.cs | 2 ++ .../src/System/String.Manipulation.cs | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/src/libraries/Common/tests/Tests/System/StringTests.cs b/src/libraries/Common/tests/Tests/System/StringTests.cs index 806c39efa529a6..64ed05a6a699b9 100644 --- a/src/libraries/Common/tests/Tests/System/StringTests.cs +++ b/src/libraries/Common/tests/Tests/System/StringTests.cs @@ -317,6 +317,8 @@ void Validate(string result) Validate(string.Concat((ReadOnlySpan)values)); Validate(string.Concat((IEnumerable)values)); Validate(string.Concat((IEnumerable)values)); // Call the generic IEnumerable-based overload + Validate(string.Concat(values.Select(s => s))); + Validate(string.Concat(new List(values))); } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsMultithreadingSupported))] diff --git a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs index 459e2afc50b7ba..367336198c4dc6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs +++ b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs @@ -152,6 +152,16 @@ public static unsafe string Concat(IEnumerable values) { ArgumentNullException.ThrowIfNull(values); + if (values.GetType() == typeof(List)) + { + return Concat(CollectionsMarshal.AsSpan((List)values)); + } + + if (values is string?[] valuesArray) + { + return Concat((ReadOnlySpan)valuesArray); + } + using (IEnumerator en = values.GetEnumerator()) { if (!en.MoveNext()) From fbe8720dc59fccbf1b24b092931349d7c3c64419 Mon Sep 17 00:00:00 2001 From: prozolic <42107886+prozolic@users.noreply.github.com> Date: Thu, 9 Jul 2026 01:57:12 +0900 Subject: [PATCH 2/2] Update src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs Co-authored-by: Miha Zupan --- .../System.Private.CoreLib/src/System/String.Manipulation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs index 367336198c4dc6..a2999577c2531c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs +++ b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs @@ -152,7 +152,7 @@ public static unsafe string Concat(IEnumerable values) { ArgumentNullException.ThrowIfNull(values); - if (values.GetType() == typeof(List)) + if (values.GetType() == typeof(List)) // avoid accidentally bypassing a derived type's reimplementation of IEnumerable { return Concat(CollectionsMarshal.AsSpan((List)values)); }