Roslyn analyzers for Utf8StringInterpolation — the zero-allocation UTF-8 string interpolation library by Cysharp. These analyzers catch usage patterns that silently defeat the library's performance guarantees at compile time, turning invisible runtime regressions into build errors.
Utf8StringInterpolation achieves zero allocation by making Utf8StringWriter<T> an interpolated string handler. When you call AppendFormat($"..."), the C# compiler routes the interpolation directly into the handler — no intermediate string is ever created.
However, Utf8StringWriter<T> also exposes Append(string?). When you write Append($"..."), the compiler sees a plain string parameter with no handler attribute, so it materializes the entire interpolated string as a heap-allocated string first, then passes it in. The code compiles cleanly, produces correct output, and silently allocates — the exact opposite of the library's purpose.
// Looks identical. Behaves very differently.
zsb.Append($"Hello, {name}!"); // allocates a string — WRONG
zsb.AppendFormat($"Hello, {name}!"); // zero allocation — correctThis package makes the wrong form a build error.
Severity: Error
Category: Performance
Before (build error):
using Utf8StringInterpolation;
var zsb = Utf8String.CreateWriter(stream);
zsb.Append($"Hello, {name}!"); // error U8SI001
zsb.Append($"You have {count} items."); // error U8SI001After (zero allocation):
zsb.AppendFormat($"Hello, {name}!");
zsb.AppendFormat($"You have {count} items.");A code fix is provided. In Visual Studio, click the lightbulb on any U8SI001 error to replace Append with AppendFormat automatically. On the command line:
dotnet format analyzers <project> --diagnostics U8SI001 --severity error
Append($"literal")with no interpolation holes is intentionally ignored. If the interpolated string contains no{...}placeholders, the compiler resolves it to a string constant at compile time — there is no heap allocation at runtime. The diagnostic only fires when actual interpolation holes are present, because those are the cases whereAppendFormatprovides a performance benefit.
<PackageReference Include="Utf8StringInterpolation.Analyzers" Version="x.y.z">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>The package contains both the analyzer and the code fix provider. It has no runtime impact — PrivateAssets="all" ensures it is not listed as a dependency of your package.
Heads up for existing codebases: Adding this package to a project that already has
Append($"...")calls produces immediate build errors. Rundotnet format analyzers --diagnostics U8SI001 --severity erroron the project to fix existing violations before (or immediately after) adding thePackageReference.
- C# projects targeting any .NET version (.NET Framework, .NET Core, .NET 5+)
- Requires the Utf8StringInterpolation NuGet package
- Tested with Visual Studio, VS Code, and
dotnet build
The analyzer registers on every InvocationExpression and checks:
- The method name is
Append - At least one argument is an
InterpolatedStringExpressionSyntaxcontaining at least one interpolation hole ({...}) - The receiver type is
Utf8StringInterpolation.Utf8StringWriter<T>(verified via semantic model, not string matching)
Because Utf8StringWriter<T>.Append has no interpolated string handler overload, any $"..." argument with holes is necessarily materialized as a heap-allocated string by the compiler. Interpolated strings without holes are compile-time constants and are excluded — they have no performance cost.
If all three conditions hold, U8SI001 is reported on the method name. The code fix rewrites the method name to AppendFormat, leaving the argument unchanged.
- Utf8StringInterpolation — the library this package guards
- ZString — the predecessor library (
Utf8StringInterpolationis its successor) - InterpolatedStringHandler — the C# feature that makes zero-allocation interpolation possible
Bug reports and pull requests welcome. The repository includes unit tests (Roslyn testing framework) and an integration test that builds a real .NET Framework project, applies the code fix via dotnet format, and verifies the result.
Every push to master publishes a new patch version automatically via Nerdbank.GitVersioning. The version is major.minor.<commit-height>. To bump major or minor, edit version.json.