Ответ 1
Я выхожу на конечность, публикуя это, но я думаю, что ответ:
Между 550 и 575
с настройками по умолчанию в Visual Studio 2015
Я создал небольшую программу, которая генерирует вложенные циклы for
...
for (int i0=0; i0<10; i0++)
{
for (int i1=0; i1<10; i1++)
{
...
...
for (int i573=0; i573<10; i573++)
{
for (int i574=0; i574<10; i574++)
{
Console.WriteLine(i574);
}
}
...
...
}
}
Для 500 вложенных циклов программа все еще может быть скомпилирована. С 575 циклами компилятор выдает:
Предупреждение Анализатор AD0001 "Microsoft.CodeAnalysis.CSharp.Diagnostics.SimplifyTypeNames.CSharpSimplifyTypeNamesDiagnosticAnalyzer" выбрал исключение типа "System.InsufficientExecutionStackException" с сообщением "Недостаточно стека, чтобы продолжить выполнение программы безопасно. Это может произойти из-за слишком большого количества функций в стеке вызовов или функции в стеке, используя слишком много пространства стека. '.
с основным сообщением компилятора
ошибка CS8078: выражение слишком длинное или сложное для компиляции
Конечно, это чисто гипотетический результат. Если самый внутренний цикл выполняет больше, чем Console.WriteLine
, тогда может быть меньше вложенных циклов до превышения размера стека. Кроме того, это может быть не строго технический предел в том смысле, что могут быть скрытые настройки для увеличения максимального размера стека для "Анализатора", упомянутого в сообщении об ошибке, или (если необходимо) для результирующего исполняемого файла. Однако эта часть ответа остается для людей, которые знают С# по глубине.
Update
В ответ на вопрос в комментариях:
Мне было бы интересно увидеть, что этот ответ расширен, чтобы "доказать" экспериментально, можете ли вы поместить 575 локальных переменных в стек, если они не используются в for-loops, и/или вы можете поместить 575 не вложенных для -loops в одной функции
В обоих случаях ответ: Да, это возможно. При заполнении метода 575 автоматически сгенерированных операторов
int i0=0;
Console.WriteLine(i0);
int i1=0;
Console.WriteLine(i1);
...
int i574=0;
Console.WriteLine(i574);
он все еще может быть скомпилирован. Все остальное меня удивило бы. Размер стека, необходимый для переменных int
, составляет всего 2,3 КБ. Но мне было любопытно, и для того, чтобы проверить дальнейшие ограничения, я увеличил это число. В конце концов, он скомпилировал не, вызывая ошибку
ошибка CS0204: допускается только 65534 локальных жителей, включая те, которые сгенерированы компилятором.
что является интересным моментом, но уже наблюдалось в другом месте: Максимальное количество переменных в методе
Аналогично, 575 не вложенных for
-loops, как в
for (int i0=0; i0<10; i0++)
{
Console.WriteLine(i0);
}
for (int i1=0; i1<10; i1++)
{
Console.WriteLine(i1);
}
...
for (int i574=0; i574<10; i574++)
{
Console.WriteLine(i574);
}
также может быть скомпилирован. Здесь я также попытался найти предел и создал больше этих циклов. В частности, я не был уверен, что переменные цикла в этом случае также считают als "locals", потому что они находятся в их собственном { block }
. Но все же более 65534 невозможно. Наконец, я добавил тест, состоящий из 40000 циклов шаблона
for (int i39999 = 0; i39999 < 10; i39999++)
{
int j = 0;
Console.WriteLine(j + i39999);
}
который содержит дополнительную переменную в цикле, но они, похоже, также считаются "локальными", и компилировать это невозможно.
Итак, чтобы суммировать: предел ~ 550 действительно вызван глубиной вложенности. Это также было сообщено сообщением об ошибке
ошибка CS8078: выражение слишком длинное или сложное для компиляции
документация об ошибке CS1647, к сожалению (но понятно) не указывает "измерение" сложности, а дает только прагматический совет
В компиляторе обрабатывался ваш код. Чтобы устранить эту ошибку, упростите свой код.
Чтобы подчеркнуть это снова: для частного случая глубоко вложенных for
-loops все это довольно академично и гипотетично. Но поиск в Интернете сообщения об ошибке CS1647 показывает несколько случаев, когда эта ошибка появилась для кода, который, скорее всего, не был намеренно сложным, но создан в реалистичных сценариях.