string.Format()参数

16

您可以向string.Format()方法传递多少参数?

在这方面应该有一些理论或强制限制。它是基于params[]类型的限制还是使用它的应用程序的内存使用情况,或者完全是其他因素?

4个回答

20

好的,我出来了......我使用了以下程序来验证发生了什么,尽管Marc指出像 "{0} {1} {2} ... {2147483647}" 这样的字符串会在参数列表之前成功地达到2 GiB 的内存限制,但我的研究结果与你的不符。因此,您可以在string.Format方法调用中放置的参数数量的硬限制为107713904

int i = 0;
long sum = 0;
while (sum < int.MaxValue)
{
    var s = sizeof(char) * ("{" + i + "}").Length;
    sum += s; // pseudo append
    ++i;
}
Console.WriteLine(i);
Console.ReadLine();

喜欢这里的讨论!


19

据我所知,没有这个限制...

理论上,数组的极限是int32的极限,但在此之前您会先遇到字符串长度的限制,我想...

只要不过分就可以了;最好将许多小片段写入文件或响应中,而不是一次性写入一个巨大的数据块。

编辑 - 看起来IL有一个限制(0xf4240),但显然这并不像它表面上那样;在我耗尽系统内存之前,我可以使其变得相当大(2^24)...


更新; 对我来说,边界点似乎是格式字符串...那些{1000001}{1000002}加起来...下面的快速计算显示,我们可以使用的有效参数的最大数量是206,449,129:

    long remaining = 2147483647;// max theoretical format arg length
    long count = 10; // i.e. {0}-{9}
    long len = 1;
    int total = 0;
    while (remaining >= 0) {
        for(int i = 0 ; i < count && remaining >= 0; i++) {
            total++;
            remaining -= len + 2; // allow for {}
        }
        count *= 10;
        len++;
    }

    Console.WriteLine(total - 1);

1
哇,任意的未记录限制... 我不喜欢那个。 +1 次研究。 - Michael Meadows
CLR不支持大于2GiB的对象。由于格式化方法为每个参数预分配了一个带有8个字符的StringBuilder,理论上的极限将是int.MaxValue /(sizeof(char)* 8),即134,217,728。 - John Leidegren
没关系,我会把它作为John的答案发布...开玩笑!我只是开个玩笑 :) +1 非常好的回答Marc - Binary Worrier
@John - 你确定8个字符的细节吗?无论参数数量如何,只有一个StringBuilder... - Marc Gravell
是的!在 string.Format(IFormatProvider,string format, params object[] args) 中,它试图分配这个新的 StringBuilder(format.Length + (args.Length * 8));最终会调用 FastAllocateString(int capacity)。我只能假设它将为每个字符分配2个字节的空间。 - John Leidegren
显示剩余2条评论

4
在Marc详细的回答上进行扩展。
唯一重要的其他限制是调试器。一旦您直接向函数传递一定数量的参数,调试器在该方法中的功能就会降低。我认为限制是64个参数。
注意:这并不意味着带有64个成员的数组,而是直接传递到函数的64个参数。
你可能会笑并说“谁会这样做?”这确实是一个合理的问题。然而,LINQ使这比您想象的要容易得多。在LINQ的内部,编译器生成了大量的代码。如果选择了超过64个字段的大型生成SQL查询,则可能会出现此问题。因为编译器在幕后需要将所有字段传递给匿名类型的构造函数。
仍然只是一个边缘案例。

3
考虑到数组类和字符串类的限制都是Int32的上限(在此处记录为2,147,483,647:Int32结构体),因此可以合理地认为这个值是格式参数数字字符串的限制。 更新经过反编译器的检查,John是正确的。使用Red Gate Reflector查看String.Format的结果如下:
public static string Format(IFormatProvider provider, string format, params object[] args)
{
    if ((format == null) || (args == null))
    {
        throw new ArgumentNullException((format == null) ? "format" : "args");
    }
    StringBuilder builder = new StringBuilder(format.Length + (args.Length * 8));
    builder.AppendFormat(provider, format, args);
    return builder.ToString();
}

代码中的format.Length + (args.Length * 8)部分足以消耗大部分数字。因此,“2,147,483,647 = x + 8x”留下了x = 238,609,294(理论值)。

当然,实际上远远不到这个数值;正如评论中的人们所提到的,字符串达到字符串长度限制的可能性非常高。

也许有人应该把这个问题编程机器问题!:P


兄弟,你真的应该直接提供一个答案 ;) - Jon Limjap
除此之外,在这两种情况下,您都会受到格式字符串的限制... {1000000} {1000001} {1000002} 等等... 这些很快就会累加起来... - Marc Gravell
@Marc - 是的,那个格式字符串本身很快就会达到2 GiB的限制... - John Leidegren
@Jon Limjap - 嗯,这有点多余,但我喜欢注释 ;) - John Leidegren

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