string.Format() parameters

2020-08-10 07:48发布

问题:

How many parameters can you pass to a string.Format() method?

There must be some sort of theoretical or enforced limit on it. Is it based on the limits of the params[] type or the memory usage of the app that is using it or something else entirely?

回答1:

OK, I emerge from hiding... I used the following program to verify what was going on and while Marc pointed out that a string like this "{0}{1}{2}...{2147483647}" would succeed the memory limit of 2 GiB before the argument list, my findings did't match yours. Thus the hard limit, of the number of parameters you can put in a string.Format method call has to be 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();

Love the discussion people!



回答2:

Not as far as I know...

well, the theoretical limit would be the int32 limit for the array, but you'd hit the string length limit long before that, I guess...

Just don't go mad with it ;-p It may be better to write lots of small fragments to (for example) a file or response, than one huge hit.

edit - it looked like there was a limit in the IL (0xf4240), but apparently this isn't quite as it appears; I can make it get quite large (2^24) before I simply run out of system memory...


Update; it seems to me that the bounding point is the format string... those {1000001}{1000002} add up... a quick bit of math (below) shows that the maximum useful number of arguments we can use is 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);


回答3:

Expanding on Marc's detailed answer.

The only other limitation that is important is for the debugger. Once you pass a certain number of parameters directly to a function, the debugger becomes less functional in that method. I believe the limit is 64 parameters.

Note: This does not mean an array with 64 members, but 64 parameters passed directly to the function.

You might laugh and say "who would do this?" which is certainly a valid question. Yet LINQ makes this a lot easier than you think. Under the hood in LINQ the compiler generates a lot of code. It's possible that for a large generate SQL query where more than 64 fields are selected that you would hit this issue. Because the compiler under the hood would need to pass all of the fields to the constructor of an anonymous type.

Still a corner case.



回答4:

Considering that both the limit of the Array class and the String class are the upper limit of Int32 (documented at 2,147,483,647 here: Int32 Structure), it is reasonable to believe that this value is the limit of the number string of format parameters.

Update Upon checking reflector, John is right. String.Format, using the Red Gate Reflector, shows the 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();
}

The format.Length + (args.Length * 8) part of the code is enough to kill most of that number. Ergo, '2,147,483,647 = x + 8x' leaves us with x = 238,609,294 (theoretical).

It's far less than that of course; as the guys in the comments mentioned the string hitting the string length limit earlier is quite likely.

Maybe someone should just code this into a machine problem! :P