C# 如何从非致命.NET异常中描述致命异常

C# 如何从非致命.NET异常中描述致命异常,c#,.net,c#-4.0,exception,fatal-error,C#,.net,C# 4.0,Exception,Fatal Error,我正在用C#编写一个通用的离散事件系统仿真库。我将在上面编写另一个库,它将实现一种特定的离散事件sim。下面是代码的完整版本 静态类引擎 { [ThreadStatic]内部静态输入时间; //... 公共静态无效运行(OneException OneException=OneException.PauseandRetrow, IList exceptionsToPass=null) { //... 当(!停止) { 事件e=currentTimeEventQueue.PopEvent(); 如

我正在用C#编写一个通用的离散事件系统仿真库。我将在上面编写另一个库,它将实现一种特定的离散事件sim。下面是代码的完整版本

静态类引擎
{
[ThreadStatic]内部静态输入时间;
//...
公共静态无效运行(OneException OneException=OneException.PauseandRetrow,
IList exceptionsToPass=null)
{
//...
当(!停止)
{
事件e=currentTimeEventQueue.PopEvent();
如果(e==null)中断;
试一试{
e、 激活();
}
捕获(引擎例外)
{
//不应该调用的引擎方法
//我打过电话,但我没有处理
//处理这种情况。。。
}
捕获(/*致命异常类型*/ex)
{
投掷;
}
捕获(例外情况除外)
{
//用于决定是否取消异常的代码
//根据此方法的参数暂停、停止、重置
}
}
}
}
问题是:我是否应该特别捕获已知不可恢复的异常类型(我不应该尝试以任何方式处理)。这些异常是什么(我可以想到
OutOfMemoryException
StackOverflowException
)。是否有致命异常的列表?我记得有些是不可追踪的因此我对可以捕获的致命异常列表感兴趣。我只想把它们重新编一遍,什么也不做。另一方面,我想处理任何其他类型的异常。或者也许我需要另一个角度


编辑:好的,我在写问题时疏忽了很多<代码>激活()是抽象的。我正在编写一个通用离散事件系统仿真库。引擎正在使用
事件的完全未知子类
。因此,它正在调用一个绝对未知的方法
Activate()
,该方法可能引发任何类型的异常。我可以忽略这个问题,但我想让调用者控制进程。从
Run()
方法的参数中可以看到,如果调用
Activate()
产生异常,调用方将决定引擎将做什么(它可以指示引擎忽略并继续,或暂停并重试,或…)。这就是为什么我要把致命的和所有其他的例外分开。如果调用方已指示引擎忽略来自
Activate()
的任何异常,则捕获并忽略致命异常是不明智的。(有龙:))

我应该特别捕获已知不可恢复的异常类型吗

不,你不应该。如果它们无法恢复,你不应该试图从中恢复

关于异常的规则是-捕获并处理您知道如何从中恢复的异常。让任何其他泡沫起来——如果这意味着应用程序崩溃,这可能是最好的

以下是代码气味,不应进行编码:

catch (/* fatal exception type*/ ex)
{
    throw;
}
没有一个可丢弃的东西真的是“不可追踪的”;可以在.NET中抛出的任何东西都是从异常派生的,因此都可以被捕获。然而,很多事情不应该被抓住。这就是你的问题;如何区分

我遵循的一般规则是“捕捉您期望的异常并知道如何处理”。这要求您首先知道代码可能抛出什么。MSDN文档通常非常擅长说明在什么情况下会抛出什么样的框架方法;除非您正在开发一个供其他编码人员使用的中间库(或者您的管理层/领导对适当的文档不太了解),否则您自己的代码库可能没有那么好的文档记录

一旦知道代码可以抛出什么,确定应该捕获什么(如果有的话)。异常捕获,也称为“口袋妖怪处理”(必须捕获它们所有)通常是一件坏事,因为有正当的理由让你的应用程序死于非命,并让用户重新启动它。示例包括StackOverflowExceptions、OutOfMemoryExceptions和各种Win32Exceptions,详细说明了为程序提供请求的资源时出现的一些内部故障。你通常无法以任何有意义的方式从中恢复过来

然而,大多数错误并没有那么严重。如果找不到文件,或者网络连接被拒绝或意外关闭,或者您试图在不检查null的情况下对类型执行某些操作(如果null检查失败,会发生什么情况?通常您无法继续,必须抛出自己的异常),则会引发异常。这些都是您应该期待、捕捉的东西,至少应该以某种可以理解的方式与最终用户进行沟通

在许多情况下,try/throw/catch是一个有用的工具,适用于预期但不是日常情况;如果您在等待结果时收到超时异常,而获取结果通常没有问题,那么甚至不要告诉用户有问题;再试一次。如果您可以(应该?)在无法计算计算时插入一些默认值(除零、可能产生非真实结果但代码无法处理这些结果的数学,等等),那么就这样做

然而,我可以想到一个场景,您必须捕获并重新执行,那就是在涉及数据库事务的情况下。如果您正在执行一个大型的“工作单元”,其中一个数据库事务处理多个持久性操作,那么如果出现任何问题,您应该回滚数据库事务。在这种情况下,操作应该被包含在一个try-catch(Exception)块中,该块捕获异常、回滚事务并重试。您可以继续的任何异常都不能