Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 捕获StackOverflowException_C#_Stack Overflow - Fatal编程技术网

C# 捕获StackOverflowException

C# 捕获StackOverflowException,c#,stack-overflow,C#,Stack Overflow,如何捕获堆栈溢出异常 我有一个允许用户编写脚本的程序,当运行任意用户代码时,我可能会得到一个StackOverflowException。运行用户代码的片段显然被try-catch包围,但在正常情况下堆栈溢出是不可修补的 我环顾了四周,这是我能找到的最有用的答案,但仍然把我带到了死胡同;从一个实例中,我发现我应该使用RuntimeHelpers.ExecuteCodeWithGuarenedCleanup调用即使在堆栈溢出后也会被调用的代码和委托,但在尝试时,进程会以堆栈溢出消息终止,而委托从未

如何捕获
堆栈溢出异常

我有一个允许用户编写脚本的程序,当运行任意用户代码时,我可能会得到一个
StackOverflowException
。运行用户代码的片段显然被
try
-
catch
包围,但在正常情况下堆栈溢出是不可修补的

我环顾了四周,这是我能找到的最有用的答案,但仍然把我带到了死胡同;从一个实例中,我发现我应该使用
RuntimeHelpers.ExecuteCodeWithGuarenedCleanup
调用即使在堆栈溢出后也会被调用的代码和委托,但在尝试时,进程会以堆栈溢出消息终止,而委托从未被调用。我尝试在handler方法上添加
preprepreparemethodattribute
,但没有改变任何事情


我还尝试使用AppDomain并处理
UnhandledException
DomainUnload
事件,但整个过程在堆栈溢出时被终止。即使我抛出新的StackOverflowException(),也会发生同样的情况而不会产生实际的堆栈溢出。

您需要在单独的进程中运行代码。

若要处理代码未处理的异常,您可以订阅AppDomains UnhandledException,这是操作系统在显示程序意外退出对话框时所处理的

在程序使用的主要方法中

var currentDomain=AppDomain.currentDomain

然后向事件添加一个处理程序

currentDomain.UnhandledException+=处理程序


在处理程序中,您可以执行任何您想要的操作,例如记录、显示错误,甚至根据需要重新初始化程序。

对脚本引擎进行编程,以跟踪脚本中的递归级别。如果递归超过任意大的数值,那么在脚本终止程序之前终止脚本。或者,您可以编程脚本引擎以无堆栈方式运行,并将脚本的所有堆栈数据存储在System.Collections.Generic.stack中。即使使用单独的堆栈,您仍然希望限制脚本可以具有的递归级别,但堆栈集合将为您提供数百倍的堆栈空间。

您必须在不同的应用程序域中加载用户脚本或任何外部第三方插件,因此,如果发生不可恢复的错误,您可以安全地卸载域

您必须创建不同的
AppDomain
,因为您无法从加载的域卸载程序集,并且不想关闭主应用程序域

您可以创建一个新的应用程序域,如下所示:

var scriptDomain = AppDomain.CreateDomain("User Scripts");
public abstract UserScriptBase : MarshaByRefObject
{
    public abstract void Execute();
}
object script = domain.CreateInstanceFromAndUnwrap(type.Location, type.FullName);
然后可以从需要创建的程序集中加载任何类型。您必须确保要加载的对象继承自
MarshalByRefObject

我假设您的用户脚本被包装在如下定义的对象中:

var scriptDomain = AppDomain.CreateDomain("User Scripts");
public abstract UserScriptBase : MarshaByRefObject
{
    public abstract void Execute();
}
object script = domain.CreateInstanceFromAndUnwrap(type.Location, type.FullName);
因此,您可以像这样加载任何用户脚本:

var scriptDomain = AppDomain.CreateDomain("User Scripts");
public abstract UserScriptBase : MarshaByRefObject
{
    public abstract void Execute();
}
object script = domain.CreateInstanceFromAndUnwrap(type.Location, type.FullName);
所有这些之后,您可以订阅
scriptDomain.UnhandledException
并监视任何不可恢复的错误

使用不同的应用程序域并不容易,您很可能会遇到一些加载/卸载问题(两个域都引用DLL)


我建议您在线查找。

然后用户仍会看到进程崩溃,包括在这种情况下出现的恼人的Windows屏幕。我如何从父进程中检测到这种情况以防止这种情况发生?你是对的,这是我尝试的第一件事,但它不起作用。我已经在问题中添加了这一点。这不会有任何帮助
StackOverflowException
终止整个过程,无论它发生在哪个
AppDomain
中。@configurator,如果它不工作,这是一个什么好主意?也许它聪明或复杂,但并不伟大。@joao并非所有好主意都能实现。有时候,一个尝试某事的想法是好的,即使它不起作用。如果你不尝试,你会成功的。听起来他在运行原始IL,而不是他自己的翻译。事实上,我在运行我自己的翻译。但是,如果可能的话,我希望有一个同样适用于原始IL的解决方案。此外,脚本可以调用任何.net函数-这意味着我无法很好地保护调用路径。您是否有一个程序可以使用脚本自动化一些任意过程,或者您的程序是脚本的文本编辑器?您的“任意用户代码”本身是脚本还是某种IL插件?现在我的程序是该语言的REPL(read-eval-print循环)。