为什么catch(Exception)错了?

时间:2011-12-05 11:22:25

标签: c# exception-handling

我已多次使用

阅读
catch (Exception ex) 
{
    Logger.LogError(ex);
}

没有重新抛出是错误的,因为你可能会隐藏其他代码中你不了解的异常。

但是,我正在编写一个WCF服务,并发现自己在几个地方这样做,以确保服务不会崩溃。 (SOA声明客户不应该知道或关心内部服务错误,因为他们不知道服务实现)

例如,我的服务从文件系统中读取数据。由于文件系统不可预测,我正在捕获读取代码中的所有异常。这可能是由于数据不良,权限问题,文件丢失等原因造成的。客户端并不关心,它只是获取“数据不可用”响应并且真正的原因记录在服务日志中 。我也不在乎,我只知道读书有问题,我不想崩溃。

现在我可以理解可能存在与文件系统无关的异常抛出。例如。也许我已经没有内存并且尝试创建一个读缓冲区已抛出异常。但事实仍然是,内存问题仍然与读取有关。我试着阅读但无法做到。也许还有足够的内存来运行其余的服务。我是否重新抛出内存异常并使服务崩溃,即使它不会导致其他任何问题?

我很欣赏只捕获你可以处理的异常的一般想法,但是如果你有一段独立的代码可以在不影响其他任何事情的情况下失败,那么可以捕获该代码产生的任何错误吗?当然,与app广泛的异常处理程序没什么不同?

编辑:澄清一下,catch不为空,记录异常。对不起,我的示例代码不好。现在已经改变了。

9 个答案:

答案 0 :(得分:2)

如果您要采用此策略,您将使部署团队很难弄清楚客户端无法工作的原因。至少记录某个地方。

答案 1 :(得分:2)

其中一个主要问题是你永远不会知道出了什么问题。不仅是您的客户/消费者隐藏了错误,您自己就是服务开发人员。

答案 2 :(得分:2)

如果磁盘上存在权限问题,我不会说您的服务按预期工作。 imho返回"Data not available"的服务甚至比返回“错误”的服务更糟糕。

假设您是您服务的用户。你打电话给它,它返回“没有数据”。你知道你的电话是正确的,但由于你没有得到任何数据,你会认为问题是你的,然后再去调查。可以用这种方式花费很多时间。

哪个更好?将错误视为错误,还是骗取用户?

<强>更新

错误取决于什么并不重要。应该处理访问问题。有时会出现故障的磁盘应该被镜像等等。作为开发人员,SOA会给您带来更多责任。隐藏错误并不会使它们消失。

SOA应该传递错误。它可能不是一个详细的错误,但它应该足以让客户端了解服务器有问题。基于此,客户端可以稍后再次尝试,或者只记录错误或通知服务台可能需要采取手动操作。

如果您返回“无数据”,则不会让您的用户有机会根据自己的意愿处理错误。

<强> UPDATE2

我确实在我的顶级使用了catch。我记录事件日志(正在监视)的异常。

您的原始问题在捕获中没有任何内容(它现在可以执行此操作)。只要你记得监视那个日志就可以了(这样你就可以纠正这些错误)。

答案 3 :(得分:1)

该代码完全没问题。确保用户收到一条好消息,例如“由于内部问题导致数据不可用。问题已记录,问题将得到解决。”每个人都很好。

这只是一个问题,如果你吃掉并吞下这个例外,以便世界上没有人会修复它。

需要始终通过编写特殊代码或仅修复导致异常的路径来处理异常。您不能总是预见到所有错误,但是一旦您意识到它们,您就可以承诺修复它们。

答案 4 :(得分:0)

我认为这个想法是为了防止遗漏错误。考虑一下:服务返回正常但未按预期执行。您必须搜索事件日志,文件日志等以查找潜在错误。如果您在其中放置跟踪写入,您可以确定原因,但可能是问题的区域和时间戳,以将错误与其他日志关联。

如果使用.NET Trace,则可以在代码中实现,直到需要时才打开它。然后调试你可以打开它而不必重新编译代码。

WCF服务可以使用FaultException将异常传递回客户端。我在构建WCF n层应用程序服务器时发现这很有用。

答案 5 :(得分:0)

确保您的服务在生产环境中不会崩溃是值得称道的。调试时,由于显而易见的原因,您需要应用程序崩溃。

然而,从你的解释中,我得到的印象是你正在捕捉你期望抛出的异常,并用空的捕获块捕获其余部分,这意味着你永远不会知道发生了什么。

将所有异常作为最后手段捕获是正确的,但请记录这些异常,它们并不比您预期的那样有趣。捕获并记录与网络,I / O,安全性,身份验证,超时,错误数据等相关的所有异常后,记录其余部分。

答案 6 :(得分:0)

一般情况下,您可以说每个例外都发生在特定情况下。出于调试目的,尽可能多地获取有关故障的信息是非常有用的,因此即将修复错误的人知道在哪里查看并可以在最短的时间内修复代码,从而为他的老板节省了一些钱。 / p>

除此之外,抛出和捕获特定异常将使您的代码更易读/更容易维护。从各个角度来看,捕获一般异常都将失败。因此,还要确保在抛出异常时,记录良好(例如,在XML注释中,因此调用者知道该方法可以抛出特定的异常)并且在出现错误时有明确的名称。还包括与问题直接相关的异常中的信息(如id等)。

答案 7 :(得分:0)

在vb.net中,一个更好的方法是“在不是IsEvilException(Ex)时捕获Ex Exception”,其中“IsEvilException”是一个布尔函数,它检查Ex是否类似OutOfMemoryException,ExecutionEngineException等。语义捕获和重新抛出异常与保留异常未被捕获的语义略有不同;如果一个特殊的“catch”语句除了“按原样”重新抛出外,对该异常不起作用,最好不要首先捕获它。

由于C#不允许异常过滤,你可能会遇到一些不太好的选择:

  1. 明确捕获并重新抛出任何“邪恶”类型的异常,然后使用毯子捕获其余部分
  2. 抓住所有异常,“按原样”重新抛出所有邪恶的异常,然后让你的逻辑处理其余的
  3. 抓住所有异常并让你的逻辑处理它们而不考虑邪恶的异常,认为如果CPU着火它将导致其他地方引发足够的其他异常,以便在持久数据获得之前关闭程序损坏。

Java和.net中异常处理的一个问题是它紧紧绑定了三个实际上有些正交的概念:

  1. 触发异常的条件或操作是什么
  2. 异常应采取行动
  3. 是否应将异常视为已解决

请注意,有时异常将涉及两种或更多类型的状态损坏(例如,尝试从流中的信息更新对象,并且读取流时出错,使流和对象都更新在糟糕的状态)。处理 条件的代码应该对异常起作用,但是在运行两个的代码之前不应该认为异常已经解决。不幸的是,没有标准模式来编码这种行为。可以向实现的任何自定义异常添加虚拟只读“已解决”属性,如果“已解决”返回false,则重新抛出任何此类异常,但没有现有异常将支持此类属性。

答案 8 :(得分:-1)

如果出现问题,那就错了。它应该崩溃。

如果代码中的某些内容崩溃,您永远无法确保正常运行。即使这意味着页面/表单一旦访问就会一直崩溃,您永远无法保证事情会继续有效,或者任何更改都会在功能上提交。

如果一个数据资源崩溃而是返回一个包含0个条目的资源,那么当应该有明显的结果时,用户将会因为没有返回任何结果而感到非常困惑。用户试图找出他做错了什么,花费了宝贵的时间。

我建议捕获所有异常(并记录它们,而不是忽略它们)的唯一情况是,如果正在运行的代码来自用户的插件/编译代码,或者某些奇怪的COM库,那么您无法控制对你自己。