
Inline adoc files when they are included exactly once. Also fix language tags because this inlining gives us better information on what language the code is written in.
108 lines
3.2 KiB
Plaintext
108 lines
3.2 KiB
Plaintext
== Why is this an issue?
|
|
|
|
In order to produce a formatted string, both `string.Create` and either `FormattableString.Invariant` or `FormattableString.CurrentCulture` can be used. However, `string.Create` rents array buffers from `ArrayPool<char>` making it more performant, as well as preventing unnecessary allocations and future stress on the Garbage Collector.
|
|
|
|
This applies to .NET versions after .NET 6, when these `string.Create` overloads were introduced.
|
|
|
|
|
|
=== What is the potential impact?
|
|
|
|
We measured a significant improvement both in execution time and memory allocation. For more details see the `Benchmarks` section from the `More info` tab.
|
|
|
|
|
|
== How to fix it
|
|
|
|
Replace calls to `FormattableString.CurrentCulture` or `FormattableString.Invariant` with calls to `string.Create(CultureInfo.CurrentCulture, ...)` or `string.Create(CultureInfo.InvariantCulture, ...)` respectively.
|
|
|
|
|
|
=== Code examples
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,csharp,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
string Interpolate(string value) =>
|
|
FormattableString.Invariant($"Value: {value}");
|
|
----
|
|
|
|
[source,csharp,diff-id=2,diff-type=noncompliant]
|
|
----
|
|
string Interpolate(string value) =>
|
|
FormattableString.CurrentCulture($"Value: {value}");
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,csharp,diff-id=1,diff-type=compliant]
|
|
----
|
|
string Interpolate(string value) =>
|
|
string.Create(CultureInfo.InvariantCulture, $"Value: {value}");
|
|
----
|
|
|
|
[source,csharp,diff-id=2,diff-type=compliant]
|
|
----
|
|
string Interpolate(string value) =>
|
|
string.Create(CultureInfo.CurrentCulture, $"Value: {value}");
|
|
----
|
|
|
|
|
|
== Resources
|
|
|
|
=== Documentation
|
|
|
|
* https://learn.microsoft.com/en-us/dotnet/api/system.string.create?view=net-7.0[string.Create]
|
|
* https://learn.microsoft.com/en-us/dotnet/api/system.formattablestring.invariant[FormattableString.Invariant]
|
|
* https://learn.microsoft.com/en-us/dotnet/api/system.formattablestring.currentculture[FormattableString.CurrentCulture]
|
|
|
|
=== Articles & blog posts
|
|
* https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated#compilation-of-interpolated-strings[Compilation of interpolated strings]
|
|
|
|
=== Benchmarks
|
|
|
|
The results were generated by running the following snippet with https://github.com/dotnet/BenchmarkDotNet[BenchmarkDotNet]:
|
|
|
|
[options="header"]
|
|
|===
|
|
| Method | Runtime | Mean | StdDev | Allocated
|
|
| StringCreate | .NET 7.0 | 152.5 ms | 3.09 ms | 83.92 MB
|
|
| FormattableString | .NET 7.0 | 191.8 ms | 6.92 ms | 198.36 MB
|
|
|===
|
|
|
|
[source,csharp]
|
|
----
|
|
int Value = 42;
|
|
DateTime Now = DateTime.UtcNow;
|
|
|
|
[Params(1_000_000)]
|
|
public int N;
|
|
|
|
[Benchmark]
|
|
public void StringCreate()
|
|
{
|
|
for (int i = 0; i < N; i++)
|
|
{
|
|
_ = string.Create(CultureInfo.InvariantCulture, $"{Now}: Value is {Value}");
|
|
}
|
|
}
|
|
|
|
[Benchmark]
|
|
public void FormattableStringInvariant()
|
|
{
|
|
for (int i = 0; i < N; i++)
|
|
{
|
|
_ = FormattableString.Invariant($"{Now}: Value is {Value}");
|
|
}
|
|
}
|
|
----
|
|
|
|
Hardware configuration:
|
|
[source]
|
|
----
|
|
BenchmarkDotNet=v0.13.5, OS=Windows 10 (10.0.19045.2728/22H2/2022Update)
|
|
11th Gen Intel Core i7-11850H 2.50GHz, 1 CPU, 16 logical and 8 physical cores
|
|
.NET SDK=7.0.203
|
|
[Host] : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2
|
|
.NET 7.0 : .NET 7.0.5 (7.0.523.17405), X64 RyuJIT AVX2
|
|
----
|
|
|