String.Format: 输入字符串的格式不正确。

40
以下代码一直给我错误提示,说“输入字符串不符合正确格式”,但我很确定它是正确的,不是吗?
int id = 112;

String[] newData = { "1", "2", "21", "reidb", "reidb", "reidb", "reidb", "aa", 
                      "Some description", "11", "2012-02-28", "2012-01-29", "true", "1", "1", 
                      "true", "note note note", "true", "1", "2011-12-03", "45"};

String data = "{ cmd: \"save magellan deal\", data: { id: {0} , AId: {1}, " +
            "CId: {2}, CCId:{3}, LA: \"{4}\", BA: \"{5}\" , " +
            "LSA: \"{6}\" , BSA: \"{7}\" , \"path: \"{8}\"," +
            "dscp: \"{9}\", SI: \"{10}\", CD: \"{11}\", " +
            "period: \"{12}\", IsStatic: {13}, LSD: {14}, LC: {15}, RB: {16},} " +
            "Notes: \"{17}\", IsEE: {18}, RBy: {19}, DPDD: \"{20}\", LId: {21} } }";


String cmd = String.Format(data, id.toString(), newData);

有人有什么想法吗?

=== 编辑 ===

修复花括号后,出现了一个新的错误:"索引(从零开始)必须大于或等于零,并且小于参数列表的大小。" 给出的 newData 为21和加上 id.toString() 后应该是精确的22?


8
您需要转义花括号。对于JSON数据,请使用两个大括号'{{'。 - LeffeBrune
1
就我个人而言,我不会为此使用 string.Format - 这只是增加了复杂性而没有好处。你无法快速确定哪个参数对应哪个占位符。字符串拼接具有相同的语义,没有需要记忆的转义规则,甚至还稍微快一点 - 然后您可以看到实际插入的变量的上下文,我假设它们在真实程序中有一些意义。 - Eamon Nerbonne
@EamonNerbonne:我同意关于复杂性的观点,但不同意速度方面的看法。在C#中,字符串是不可变的,因此像这种情况下进行多个字符串连接可能会更慢。然而,对于大多数用例来说,性能差异不太重要,因此我更倾向于使用更清晰、更易维护的代码而不是String.Format。 - Eric J.
2
这是相当糟糕的代码。你至少考虑过使用真正的JSON序列化器吗? - Hans Passant
@Eric J. 字符串可能是不可变的,但在幕后,string.Format 需要通过连接构建一个新字符串。此外,它还需要解析格式字符串——这是一件不免费的事情;这很可能是整个操作中最昂贵的部分。相比之下,一堆内联字符串连接被C#编译器优化为只有一个concat调用,即比string.JoinStringBuilder稍快。因此,没有技术上避免它的理由;而且你的代码将更易读。 - Eamon Nerbonne
显示剩余4条评论
5个回答

80

在格式字符串中,需要对“{”和“}”进行转义(通过复制它们):

"{{ cmd: \"save magellan deal\", data: {{ id: {0} , AId: {1}, " +
"CId: {2}, CCId:{3}, LA: \"{4}\", BA: \"{5}\" , " +
"LSA: \"{6}\" , BSA: \"{7}\" , \"path: \"{8}\"," +
"dscp: \"{9}\", SI: \"{10}\", CD: \"{11}\", " +
"period: \"{12}\", IsStatic: {13}, LSD: {14}, LC: {15}, RB: {16},}} " +
"Notes: \"{17}\", IsEE: {18}, RBy: {19}, DPDD: \"{20}\", LId: {21} }} }}"

您在格式字符串中有22个元素,而在数组中有21个。


嗯,改成双括号后,原来的错误消失了,但是出现了“索引必须大于或等于0且小于参数列表大小”的错误。在 newData + extra id.toString() 中有21个字符,应该是22个... - jamesdeath123
3
似乎完全放弃这种方法并只使用带有一些快速创建的匿名对象的JSON编码器是一个非常好的理由。这样会大大减少出错的可能性。 - spender
1
第一次知道在C#的格式化字符串中需要转义花括号。 - macio.Jun

8

你在newData中有21个元素,但使用了22个占位符(编号从0到21)。

此外,您必须转义输入数据中的文字“{”。

打开和关闭大括号被解释为开始和结束格式项。因此,您必须使用转义序列来显示文字“{”或“}”。在固定文本中指定两个打开大括号(“{{”)以显示一个打开大括号(“{”),或者指定两个闭合大括号(“}}”)以显示一个闭合大括号(“}”)。格式项中的大括号按照遇到它们的顺序逐个解释。不支持解释嵌套的大括号。

http://msdn.microsoft.com/en-us/library/txafckwd.aspx


我第一次发布时错过了id,但在我的代码中我确实有它,但仍然出现错误。 - jamesdeath123

3

我之前在评论中已经说过了,但我认为现在值得回答:

不要使用 string.Format(在这种情况下)。它速度较慢,可读性较差。如果您需要复杂的拼接,请使用有意义的变量名称进行简单的字符串连接-这将更快且更易于维护。由于编译器优化,对于固定数量的段落而言,直接使用 +最快的选项,并且更易于维护,因为读者可以看到变量放置在字符串上下文中。

正如Hans Passant所指出的那样,看起来你正在创建一个javascript文字。如果是这种情况,请考虑使用Json序列化器,例如Json.NET

JsonConvert.SerializeObject(new {
    cmd = "save magellan deal",
    data = new {
        id = 12345, AId = 1, CId = 2, CCId = 21,
        LA = "reidb", BA = "reidb", LSA = "reidb", BSA = "reidb",
        path = "aa", dscp = "Some description", SI = 11,
        CD = "2012-02-28", period = "2012-01-29",
        IsStatic = true, LSD = 1, LC = 1, RB = true,
    },
    Notes = "note note note",
    IsEE = true, RBy = 1, DPDD = "2011-12-03", LId = 45
})

虽然Json.NET支持DateTime序列化,但JS中没有标准的日期格式,因此它们以iso 8601格式的字符串序列化。这可能不是您需要的,因此在此示例中使用日期字符串-首先尝试使用iso格式,因为这是最简单的解决方案。


2

除了转义大括号外,还可以尝试将String[]的定义更改为:

int id = 112;

String[] newData = {id.ToString(), "1", "2", "21", "reidb", "reidb", "reidb", "reidb", "aa", 
          "Some description", "11", "2012-02-28", "2012-01-29", "true", "1", "1", 
          "true", "note note note", "true", "1", "2011-12-03", "45"};

并将您的String.Format更改为:

String cmd = String.Format(data,newData);

1
@jamesdeath123 - 或者,正如我刚刚输入的那样,您只有两个参数来填充格式字符串中的22个位置。并且需要根据Cédric Bignon的要求转义文字大括号。 - HABO

1

什么

String cmd = String.Format(data, id.toString(), newData);  

这是在尝试格式化字符串数据,只使用2个字符串而不是22个字符串!!
哪两个字符串?...1)id.ToString()和2)newData.ToString()
显然是错误的。

如何看出这是问题所在?只需在数据字符串中保留{0}和{1}并打印它。它可以编译,看看你得到什么。
当然,在想要字符串文字的地方必须使用{{而不是{

完全可行的解决方案:

int id = 112;

String[] newData = { id.ToString(),"1", "2", "21", "reidb", "reidb", "reidb", "reidb", "aa", 
                  "Some description", "11", "2012-02-28", "2012-01-29", "true", "1", "1", 
                  "true", "note note note", "true", "1", "2011-12-03", "45"};

String data = "{{ cmd: \"save magellan deal\", data: {{ id: {0} , AId: {1}, " +
                    "CId: {2}, CCId:{3}, LA: \"{4}\", BA: \"{5}\" , " +
                    "LSA: \"{6}\" , BSA: \"{7}\" , \"path: \"{8}\"," +
                    "dscp: \"{9}\", SI: \"{10}\", CD: \"{11}\", " +
                    "period: \"{12}\", IsStatic: {13}, LSD: {14}, LC: {15}, RB: {16},}} " +
                    "Notes: \"{17}\", IsEE: {18}, RBy: {19}, DPDD: \"{20}\", LId: {21} }} }}";


String cmd = String.Format(data, newData);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接