【问题标题】:Interpolated string formatting issue插值字符串格式问题
【发布时间】:2026-01-25 15:40:01
【问题描述】:

我已经多次偶然发现一个与插值字符串有关的问题。

考虑以下情况:

double number = 123.4567;
var str = $"{{{number:F2}}}"; //I want to get "{123.45}"
Console.WriteLine(str); // Will print "{F2}"

起初有点令人惊讶,但一旦你意识到大括号是如何配对的,它就会变得有意义。接下来的两个大括号是插值字符串中单个大括号的转义序列。所以插值表达式的左括号与字符串中的最后一个花括号配对。

     ___pair____
    |           |
$"{{{number:F2}}}";

现在您可以执行以下操作来中断转义序列:

var str = $"{{{number:F2} }}"; // This will be "{123.45 }"

请注意这种方法添加到输出中的空格字符。 (不理想)

我的问题:

假设我想使用 单个插值字符串 来准确获取输出“{123.45}”

如果不做类似以下的骇人听闻的事情,这是否可能?

var s = $"{{{number:F2}{'}'}";

【问题讨论】:

  • 要得到想要的输出,你可以用ToString作弊:$"{{{number.ToString("F2")}}}"
  • @Xiaoy312 可能是目前最好的解决方案。我不得不说,这有点不直观,在这种情况下它以不同的方式解决了括号的奇偶性。
  • 您对$"{{{$"{number:F2}"}}}" 感觉如何?我想从技术上讲它是两个字符串,但至少它不会破坏解析器。与@Xiaoy312 思路相同,分别格式化并插入到字符串中。这是具有奇怪解析规则的格式,类似于如果您想使用条件 (?:) 运算符,则必须执行的解决方法,冒号的存在会导致问题。
  • 也许另一个不那么骇人听闻的选择就是破坏字符串。 $"{{{number:F2}"+"}",

标签: c# .net c#-6.0


【解决方案1】:

这是字符串插值的预期行为。在thisMicrosoft 文档中提到了它。以下内容仅来自微软链接。

左大括号和右大括号被解释为格式项的开始和结束。因此,您必须使用转义序列来显示文字左大括号或右大括号。在固定文本中指定两个左大括号("{{") 以显示一个左大括号("{"),或指定两个右大括号("}}") 以显示一个右大括号("}")。格式项中的大括号按照遇到的顺序依次解释。不支持解释嵌套大括号。

转义大括号的解释方式可能会导致意想不到的结果。例如,考虑格式项“{{{0:D}}}”,它旨在显示一个左大括号、一个格式化为十进制数的数值和一个右大括号。但是,格式项实际上是通过以下方式解释的:

  • 前两个左大括号("{{") 被转义并产生一个 左大括号。
  • 接下来的三个字符("{0:") 被解释为一个开始 格式项。
  • 下一个字符("D") 将被解释为十进制标准 数字格式说明符,但接下来的两个转义大括号 ("}}") 产生一个大括号。因为生成的字符串 ("D}") 不是 标准数字格式说明符,结果字符串为 解释为自定义格式字符串,表示显示文字 字符串"D}"
  • 最后一个大括号("}") 被解释为格式项的结尾。
  • 显示的最终结果是文字字符串"{D}"。这 不显示要格式化的数值。

编写代码以避免误解转义大括号和格式化项目的一种方法是分别格式化大括号和格式化项目。即在第一个格式操作中显示一个文字左大括号,在下一个操作中显示格式项的结果,然后在最后一个操作中显示一个文字右大括号。以下示例说明了这种方法。

int value = 6324;
string output = string.Format("{0}{1:D}{2}", 
                             "{", value, "}");
Console.WriteLine(output);
// The example displays the following output:
//       {6324}  

【讨论】:

    【解决方案2】:

    假设不需要使用命名格式字符串,可以使用:

    var s = $"{{{number:#.#0}}}";
    

    【讨论】: