dotnet/roslyn
GitHub で見る`nameof(X)` in Interpolated String Handlers are not always lowered to constants
Open
#67,295 opened on 2023年3月14日
Area-CompilersConcept-Continuous Improvementhelp wanted
Repository metrics
- Stars
- (20,414 stars)
- PR merge metrics
- (平均マージ 6d 17h) (30d で 256 merged PRs)
説明
Version Used: sharplab.io; main (24 Jan 2023)
Steps to Reproduce:
- Use an interpolated string with a constant string and a
nameofexpression. - Observe the whole string lowered to a constant.
- Change the interpolated string to add a property.
- Observe the
nameofexpression is now lowered toAppendFormatted(notAppendLiteral)
Source:
public int Property => 2;
public void Test() {
Console.WriteLine($"abc {nameof(Test)}");
Console.WriteLine($"abc {nameof(Test)} {Property}");
}
Expected Behavior:
public void Test()
{
Console.WriteLine("abc Test");
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(9, 1);
defaultInterpolatedStringHandler.AppendLiteral("abc Test "); // <-- merged
defaultInterpolatedStringHandler.AppendFormatted(Property);
Console.WriteLine(defaultInterpolatedStringHandler.ToStringAndClear());
}
Actual Behavior:
public void Test()
{
Console.WriteLine("abc Test");
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(5, 2);
defaultInterpolatedStringHandler.AppendLiteral("abc ");
defaultInterpolatedStringHandler.AppendFormatted("Test"); // <-- not merged
defaultInterpolatedStringHandler.AppendLiteral(" ");
defaultInterpolatedStringHandler.AppendFormatted(Property);
Console.WriteLine(defaultInterpolatedStringHandler.ToStringAndClear());
}
Note how the nameof expression was combined with the literal string next to it in the first, but not in the second. In addition, the second one lowers the nameof into an AppendFormatted call instead of an AppendLiteral.
Performance
public class InterpolatedBenchmarks
{
#pragma warning disable CA1822
public int Property => 2;
#pragma warning restore CA1822
[Benchmark(Baseline = true)]
public string TestA() =>
"test TestB " + Property;
[Benchmark]
public string TestB() =>
$"test TestB {Property}";
[Benchmark]
public string TestC() =>
$"test {nameof(TestB)} {Property}";
}
Running the above benchmark (with BenchmarkDotNet) on 7.0.323.6910 (x64 RyuJIT AVX2) shows a slight performance decrease for the actual compiler output compared to what I would expect:
| Method | Mean | Error | StdDev | Ratio | RatioSD |
|---|---|---|---|---|---|
| TestA | 14.84 ns | 0.343 ns | 0.321 ns | 1.00 | 0.00 |
| TestB | 36.03 ns | 0.702 ns | 0.656 ns | 2.43 | 0.08 |
| TestC | 46.31 ns | 0.516 ns | 0.458 ns | 3.12 | 0.08 |
In fact, performance is horrible compared to plain concatenation (lowered to string.Concat).