This is an expected behavior of string interpolation. It is mentioned at this Microsoft document. The below content is from Microsoft link only.
Opening and closing braces are interpreted as starting and ending a format item. Consequently, you must use an escape sequence to display a literal opening brace or closing brace. Specify two opening braces ("{{") in the fixed text to display one opening brace ("{"), or two closing braces ("}}") to display one closing brace ("}"). Braces in a format item are interpreted sequentially in the order they are encountered. Interpreting nested braces is not supported.
The way escaped braces are interpreted can lead to unexpected results. For example, consider the format item "{{{0:D}}}", which is intended to display an opening brace, a numeric value formatted as a decimal number, and a closing brace. However, the format item is actually interpreted in the following manner:
- The first two opening braces
("{{") are escaped and yield one
opening brace.
- The next three characters
("{0:") are interpreted as the start of a
format item.
- The next character
("D") would be interpreted as the Decimal standard
numeric format specifier, but the next two escaped braces ("}}")
yield a single brace. Because the resulting string ("D}") is not a
standard numeric format specifier, the resulting string is
interpreted as a custom format string that means display the literal
string "D}".
- The last brace
("}") is interpreted as the end of the format item.
- The final result that is displayed is the literal string,
"{D}". The
numeric value that was to be formatted is not displayed.
One way to write your code to avoid misinterpreting escaped braces and format items is to format the braces and format item separately. That is, in the first format operation display a literal opening brace, in the next operation display the result of the format item, then in the final operation display a literal closing brace. The following example illustrates this approach.
int value = 6324;
string output = string.Format("{0}{1:D}{2}",
"{", value, "}");
Console.WriteLine(output);
// The example displays the following output:
// {6324}
ToString:$"{{{number.ToString("F2")}}}"$"{{{$"{number:F2}"}}}"? I guess technically it's two strings, but at least it doesn't break the parser. Same idea as @Xiaoy312, format separately and insert into the string. It's the formatting that has the odd parsing rules, similar to the workarounds you have to do if you want to use the conditional (?:) operator, the existence of the colon causes issues.$"{{{number:F2}"+"}",