我明白为什么代码无法正常工作。我不明白技术原因是什么,所以我们不会得到更明确的错误消息。
在开发netcore2应用程序时,我最终使用构造函数进行循环引用。我的意思是类A的构造函数实例化了另一个类型为B的对象,它本身会实例化一个类型为A的对象,依此类推。
这是一个简单的代码片段,用于重现循环实例化,在我创建该示例的online compiler上抛出StackOverflowException
。
public class A
{
public A()
{
var b = new B();
}
}
public class B
{
public B()
{
var b = new B();
}
}
public class Program
{
public static void Main(string[] args)
{
var a = new A();
}
}
令人惊讶的是,在应用程序崩溃之前,IIS给了我一个502.3 - Bad Gateway
错误,而不是堆栈溢出异常,而这并没有提供有关底层问题的大量信息。我希望像这样的循环调用是一个容易检测的模式,它不仅可以被编译器捕获,而且甚至可以被VisualStudio 2017或Resharper终极针对,但没有任何事情警告过我。
this article以及this one似乎表明问题可能是超时但似乎不太可能,因为应用程序会在两秒钟内崩溃。
我根本不明白为什么没有CircularConstructionException
- 这听起来很容易实现,更糟糕的是,为什么IIS没有像在线编译器一样抛出常规StackOverflowException
?
答案 0 :(得分:3)
我相信正确的答案是它是C#的设计决定。在您的情况下,其他异常被捕获并包装在异常页面中,StackOverflowException
会导致进程终止,这是报告502.3响应(报告连接失败)的原因。
在StackOverflowException s上的MSDN页面:
在.NET的早期版本中 框架,您的应用程序可以 捕获StackOverflowException对象 (例如,从中恢复 无限递归)。但是,那 目前气馁 因为重要的额外代码是 需要可靠地捕获堆栈 溢出异常并继续 程序执行。
从.NET Framework开始 版本2.0,StackOverflowException try-catch无法捕获对象 块和相应的过程是 默认终止。因此, 建议用户编写代码 检测和防止堆栈 溢出。例如,如果你的 应用程序取决于递归,使用 反击或国家条件 终止递归循环。注意 托管的应用程序 公共语言运行库(CLR)可以 指定CLR卸载 应用程序域所在的堆栈 溢出异常发生并让 相应的过程继续。对于 更多信息,请参阅 ICLRPolicyManager接口和 托管公共语言运行时。
答案 1 :(得分:2)
我根本不明白为什么没有CircularConstructionException - 这听起来很容易实现
在运行时,对于实例化另一个对象的对象,即使是相同类型,也没有任何违法行为。问题是您没有正确控制堆栈,因此StackOverflowException
实际上是合适的。在这种情况下,可以说编译器可以检测到该问题,但这仍然不是运行时异常。
更糟糕的是,为什么IIS不像在线编译器那样抛出常规的StackOverflowException?
IIS可能不知道为什么它会死亡。它创建了一个工作进程来运行您的应用程序;该进程因堆栈溢出而死亡。然后,IIS主机进程返回错误,指示工作进程失败。也许“Bad Gateway”不是最明确的,但是IIS主机对堆栈溢出一无所知。它只是知道它的工作进程没有响应或死亡。
答案 2 :(得分:0)
此类调用itsef不定时并导致堆栈溢出
public class B
{
public B()
{
var b = new B();
}
}