Skip to content

Commit eaf202c

Browse files
committed
fix: CS0121 in earlier C# versions for Append with string-like types
1 parent 28e36a5 commit eaf202c

4 files changed

Lines changed: 99 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ All notable changes to **ValueStringBuilder** will be documented in this file. T
66

77
## [Unreleased]
88

9+
### Fixed
10+
11+
- Resolved `CS0121` overload ambiguity when passing a no-hole interpolated string (e.g. `Append($"text")`) to `Append`/`AppendLine` on C# 13 and earlier, by adding `Append(string?)` and `AppendLine(string?)` overloads. Reported by [@SMAH1](https://github.com/SMAH1) in #283
12+
913
## [3.4.1] - 2026-02-19
1014

1115
### Fixed

src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,13 @@ ref Unsafe.As<char, byte>(ref strRef),
8686
bufferPosition += str.Length;
8787
}
8888

89+
/// <summary>
90+
/// Appends a string.
91+
/// </summary>
92+
/// <param name="value">The string to be added to this builder.</param>
93+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
94+
public void Append(string? value) => Append(value.AsSpan());
95+
8996
/// <summary>
9097
/// Appends a character buffer.
9198
/// </summary>
@@ -158,6 +165,17 @@ public void AppendLine(scoped ReadOnlySpan<char> str)
158165
Append(Environment.NewLine);
159166
}
160167

168+
/// <summary>
169+
/// Calls <see cref="Append(string)"/> and appends <see cref="Environment.NewLine"/>.
170+
/// </summary>
171+
/// <param name="value">The string to be added to this builder.</param>
172+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
173+
public void AppendLine(string? value)
174+
{
175+
Append(value.AsSpan());
176+
Append(Environment.NewLine);
177+
}
178+
161179
/// <summary>
162180
/// Appends a span of the given length, which can be written to later.
163181
/// </summary>

tests/LinkDotNet.StringBuilder.UnitTests/ValueStringBuilder.Append.Tests.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,4 +253,38 @@ public void GivenStringBuilder_WhenAddingIncreasinglyLargerStrings_ThenShouldBeA
253253

254254
builder.ToString().ShouldMatch("[a]{256}[b]{512}[c]{1024}[d]{2048}[e]{4096}[f]{8192}");
255255
}
256+
257+
[Fact]
258+
public void ShouldAppendVerbatimString()
259+
{
260+
using var builder = new ValueStringBuilder();
261+
262+
builder.Append(@"C:\temp");
263+
264+
builder.ToString().ShouldBe(@"C:\temp");
265+
}
266+
267+
[Fact]
268+
public void ShouldAppendRawStringLiteral()
269+
{
270+
using var builder = new ValueStringBuilder();
271+
272+
builder.Append("""raw""");
273+
274+
builder.ToString().ShouldBe("raw");
275+
}
276+
277+
[Theory]
278+
[InlineData("\n", "\n")]
279+
[InlineData("\r\n", "\r\n")]
280+
[InlineData("\t", "\t")]
281+
[InlineData("\\", "\\")]
282+
public void ShouldAppendEscapeAndLineTerminatorSequences(string value, string expected)
283+
{
284+
using var builder = new ValueStringBuilder();
285+
286+
builder.Append(value);
287+
288+
builder.ToString().ShouldBe(expected);
289+
}
256290
}

tests/LinkDotNet.StringBuilder.UnitTests/ValueStringBuilder.InterpolatedString.Tests.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,49 @@ public void ShouldClearAndThenAppendInterpolatedString()
9090
builder.ToString().ShouldBe("New 1");
9191
}
9292

93+
[Fact]
94+
public void ShouldAppendNoHoleInterpolatedString()
95+
{
96+
using var builder = new ValueStringBuilder();
97+
98+
// Regression guard: a no-hole interpolated string is a constant that converts to both
99+
// ReadOnlySpan<char> and AppendInterpolatedStringHandler. On C# 13 and earlier this was
100+
// ambiguous (CS0121) because ValueStringBuilder had no Append(string) overload.
101+
builder.Append($"Test1\n");
102+
103+
builder.ToString().ShouldBe("Test1\n");
104+
}
105+
106+
[Fact]
107+
public void ShouldAppendLineNoHoleInterpolatedString()
108+
{
109+
using var builder = new ValueStringBuilder();
110+
111+
builder.AppendLine($"NoHole");
112+
113+
builder.ToString().ShouldBe($"NoHole{Environment.NewLine}");
114+
}
115+
116+
[Fact]
117+
public void ShouldAppendNoHoleVerbatimInterpolatedString()
118+
{
119+
using var builder = new ValueStringBuilder();
120+
121+
builder.Append($@"C:\temp");
122+
123+
builder.ToString().ShouldBe(@"C:\temp");
124+
}
125+
126+
[Fact]
127+
public void ShouldAppendNoHoleRawInterpolatedString()
128+
{
129+
using var builder = new ValueStringBuilder();
130+
131+
builder.Append($"""raw""");
132+
133+
builder.ToString().ShouldBe("raw");
134+
}
135+
93136
private class CustomType
94137
{
95138
public string Value { get; set; } = string.Empty;

0 commit comments

Comments
 (0)