Skip to content

Appending formatted StringBuilder into itself requires documenting on reference #105957

@karakasa

Description

@karakasa

Description

When I was writing the API proposal #105870 (implement ISpanFormattable on StringBuilder), I found that currently the following behavior is not correctly handled, or not properly documented.

When you are using StringBuilder.Append($"a{StringBuilder itself}b"), the result doesn't look right. I understand it’s on the breaking change list, but I think we should document it on the reference page which says nothing about it as of now. A source analyzer will be better.

Reproduction Steps

using System;
using System.Text;

var sb = new StringBuilder("f(x)");
sb.Append($"f({sb})");
Console.WriteLine(sb);

https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEUCuA7AHwAEAmARgFgAoIgBgAIiyA6AFRgQwG5rqA3AIZR6AZ2D0AvPTwwA7vQDKGKAEs8AcwBCOFQBsAJjCgAKAEQAzYwgCUp6zypjmAQQAOrmHn3GAJBeMA3mIAvrb21EwAnMZi9kA

Expected behavior

The code prints f(x)f(f(x)).

Actual behavior

The code prints f(x)f(f(x)f()

Regression?

Pre-6.0 versions print abc because they don't have AppendInterpolatedStringHandler.

Known Workarounds

sb.Append($"f({sb.ToString()})");

Configuration

No response

Other information

The "bug" is due to how AppendInterpolatedStringHandler handles sections of interpolated strings. The aforementioned code is compiled into:

        StringBuilder stringBuilder = new StringBuilder("f(x)");
        StringBuilder stringBuilder2 = stringBuilder;
        StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(3, 1, stringBuilder2);
        handler.AppendLiteral("f(");
        handler.AppendFormatted(stringBuilder);
        handler.AppendLiteral(")");
        stringBuilder2.Append(ref handler);
        Console.WriteLine(stringBuilder);

So when handler.AppendFormatted is called, there's already content in StringBuilder.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions