【问题标题】:string.Format() parametersstring.Format() 参数
【发布时间】:2009-02-18 13:19:53
【问题描述】:

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

它必须有某种理论上的或强制的限制。它是基于 params[] 类型的限制,还是使用它的应用程序的内存使用量,还是完全基于其他东西?

【问题讨论】:

    标签: c# language-features


    【解决方案1】:

    好的,我从隐藏中出来了...我使用以下程序来验证发生了什么,而 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();
    

    喜欢讨论的人!

    【讨论】:

      【解决方案2】:

      据我所知没有...

      好吧,理论上的限制是数组的 int32 限制,但我猜你早就达到了字符串长度限制...

      只是不要对它发疯 ;-p 将大量小片段写入(例如)文件或响应可能比一个巨大的命中更好。

      edit - 它看起来在 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 用于研究。
      • CLR 不支持大于 2GiB 的对象。因为格式方法为每个参数预分配了一个带有 8 个字符的 StringBuilder,所以一个理论限制是 int.MaxValue/(sizeof(char)*8) 等于 134,217,728
      • 没关系,我会把它作为约翰的答案发布。 . .开玩笑!我只是在开玩笑:) +1 很好的回答马克
      • @John - 你确定 8 个字符的详细信息吗? StringBuilder 只有一个,不管参数有多少……
      • 是的!转到 string.Format(IFormatProvider,string format, params object[] args) 它尝试分配这个新的 StringBuilder(format.Length + (args.Length * 8));最终调用 FastAllocateString(int capacity) 我只能假设它将为每个字符分配 2 个字节。
      【解决方案3】:

      扩展 Marc 的详细答案。

      唯一重要的其他限制是调试器。一旦将一定数量的参数直接传递给函数,调试器在该方法中的功能就会降低。我相信限制是 64 个参数。

      注意:这并不是说一个有 64 个成员的数组,而是直接传递给函数的 64 个参数。

      你可能会笑着说“谁会这样做?”这当然是一个有效的问题。然而 LINQ 使这比您想象的要容易得多。在 LINQ 的内部,编译器会生成大量代码。对于选择了超过 64 个字段的大型生成 SQL 查询,您可能会遇到此问题。因为引擎盖下的编译器需要将所有字段传递给匿名类型的构造函数。

      仍然是一个角落案例。

      【讨论】:

        【解决方案4】:

        考虑到Array类和String类的限制都是Int32的上限(记录在2,147,483,647这里:Int32 Structure),有理由相信这个值是格式的数字字符串的限制参数。

        更新检查反射器后,John 是对的。 String.Format,使用Red Gate Reflector,显示ff:

        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(理论值)。

        当然远少于那个;正如 cmets 中的人提到的字符串很可能达到字符串长度限制。

        也许有人应该把它编码成机器问题! :P

        【讨论】:

        • 老兄,你真的应该提供一个答案;)
        • 此外 - 在这两种情况下,格式字符串都会更妨碍您...... {1000000}{1000001}{1000002} 等等......它加起来很快......
        • @Marc - 是的,格式字符串本身应该很快达到 2 GiB 的限制......
        • @Jon Limjap - 这有点多余,我喜欢 cmets ;)
        猜你喜欢
        • 2010-11-28
        • 2014-05-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-24
        相关资源
        最近更新 更多