我发这个帖子有点冒险,但我认为答案是:
介于 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,则在超出堆栈大小之前可能会出现更少的嵌套循环。此外,这可能不是严格的技术限制,因为可能存在隐藏设置以增加错误消息中提到的“分析器”或(如有必要)生成的可执行文件的最大堆栈大小。然而,这部分答案留给深入了解 C# 的人。
更新
回复question in the comments:
我很想看到这个答案扩展为通过实验“证明”如果它们 不 在 for 循环中使用,你是否可以将 575 个局部变量放在堆栈上,和/或你是否可以将 575 个 非嵌套 for 循环放在一个函数中
对于这两种情况,答案都是:是的,有可能。当用 575 条自动生成的语句填充方法时
int i0=0;
Console.WriteLine(i0);
int i1=0;
Console.WriteLine(i1);
...
int i574=0;
Console.WriteLine(i574);
它仍然可以编译。其他一切都会让我感到惊讶。 int 变量所需的堆栈大小仅为 2.3 KB。但我很好奇,为了测试进一步的限制,我增加了这个数字。最终,它没有编译,导致错误
错误 CS0204:仅允许 65534 个本地变量,包括编译器生成的本地变量
这是一个有趣的点,但已经在其他地方观察到:Maximum number of variables in method
同样,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);
}
也可以编译。在这里,我也试图找到极限,并创建了更多这样的循环。特别是,我不确定这种情况下的循环变量是否也算作“本地人”,因为它们在自己的{ block } 中。但是,超过 65534 仍然是不可能的。最后,我添加了一个包含 40000 个循环模式的测试
for (int i39999 = 0; i39999 < 10; i39999++)
{
int j = 0;
Console.WriteLine(j + i39999);
}
在循环中包含一个附加变量,但这些似乎也算作“本地变量”,因此无法编译。
总结一下:~550 的限制确实是由循环的嵌套深度造成的。错误消息也表明了这一点
错误 CS8078:表达式太长或太复杂而无法编译
不幸的是(但可以理解)documentation of error CS1647 没有指定复杂性的“度量”,而只是给出了务实的建议
在处理您的代码的编译器中出现堆栈溢出。要解决此错误,请简化您的代码。
再次强调这一点:对于深度嵌套的for-loops 的特殊情况,所有这些都是相当学术和假设的。但是,通过网络搜索 CS1647 的错误消息,可以发现在几个情况下,出现此错误的代码很可能不是故意复杂的,而是在现实场景中创建的。