在C#中捕获StackOverflow异常的好方法是什么?

4

如果我有一个方法,我知道它可能会无限递归,但我无法可靠地预测什么条件/参数会导致它,那么在C#中做到这一点的好方法是什么:

try
{
  PotentiallyInfiniteRecursiveMethod();
}
catch (StackOverflowException)
{
  // Handle gracefully.
}

显然在主线程中无法做到这一点,但我已经被告知可以使用线程或AppDomain来实现,但我从未见过可靠的工作示例。有人知道如何可靠地完成这项任务吗?


你能重新设计你的算法吗? - the_drow
这并不一定是我的算法的问题;例如,如果XSLT中有一个递归模板,则XslCompiledTransform对象上的Transform方法将会出错。 - Flynn1179
这并不一定是我的XSLT,而且那只是一个例子。 - Flynn1179
+1,非常有趣的问题。我的第一反应是:“原则上不可能”,但由于异常会取消堆栈,所以这其实是可以做到的。 - Konrad Rudolph
2个回答

11

你做不到。来自MSDN

从.NET Framework版本2.0开始,try-catch块无法捕获StackOverflowException对象,并且默认情况下相应的进程会终止。因此,建议用户编写代码以检测和防止堆栈溢出。例如,如果您的应用程序依赖于递归,请使用计数器或状态条件来终止递归循环。请注意,托管公共语言运行时(CLR)的应用程序可以指定CLR卸载发生堆栈溢出异常的应用程序域并让相应的进程继续运行。有关更多信息,请参见ICLRPolicyManager接口和托管概述。


实际上,从那段代码片段来看,我认为你是可以的;它明确表示,如果发生异常的应用程序域被卸载,进程将继续。这意味着可以在自己的应用程序域中运行该方法;我的问题是,如何做到这一点? - Flynn1179
这个链接可能会很有用: http://msdn.microsoft.com/en-us/library/dd380850.aspx。它描述了如何加载新应用程序域。也许这可能是最优雅的想法。但是,托管一个全新的AppDomain似乎有点过度杀伤力了... 你能验证具有循环引用的XSLT吗? - Arcturus
这并不是一件简单的事情,但这也不是重点;我正在寻找一个通用的解决方案,无论什么原因导致了堆栈溢出。 - Flynn1179
对于更通用的解决方案,我认为你需要深入该领域。我不认为这会更容易。 :( - Arcturus

1

无法捕获 StackOverflowException,但您可以处理未处理的异常:

static void Main()
{
AppDomain.CurrentDomain.UnhandledException += 
  new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
}

static void CurrentDomain_UnhandledException
  (object sender, UnhandledExceptionEventArgs e)
{
  try
  {
    Exception ex = (Exception)e.ExceptionObject;

    MessageBox.Show("Whoops! Please contact the developers with the following" 
          + " information:\n\n" + ex.Message + ex.StackTrace, 
          "Fatal Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
  }
  finally
  {
    Application.Exit();
  }
}

那不会在 StackOverflow 异常上触发,我已经尝试过了;至少不是从 AppDomain.CurrentDomain 内部触发。 - Flynn1179

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接