Improve performance of Path.ChangeExtension (dotnet/coreclr#21766)
In the common case where it need to replace a non-empty extension with a non-empty extension, it currently incurs a substring without the original extension prior to then concatenating with the new extension. This PR avoids that.
(As the Path implementation is in corelib, this uses string.FastAllocateString and then formats into it with a span; if we wanted to avoid that, string.Create could also be used.)
* Add internal String.Concat overloads for spans
* Use span-based string.Concat overloads in several places
Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>