2011-08-22 61 views
15

我有一个应用程序运行一个很长的批处理过程,可能会抛出许多异常。如果在批次中的一个项目中引发了非关键异常,我只想简单地记录它并继续,以便稍后解决问题,同时让其他批次项目继续。我应该捕捉哪些异常?

一些例外情况(如OutOfMemoryException)对应用程序整体而言具有破坏性,而且我希望重新抛出它们,以便它们冒泡到全局异常处理程序,它将记录错误并停止应用程序。

所以我的问题是,有没有我可以在我的下异常处理程序重新抛出,同时抑制其他一切(登录后)临界异常的reasonbly短名单?

谢谢!

编辑:要详细一点,这里是我的程序的基本结构

foreach(var item in longItemList) 
{ 
    try 
    { 
     bigDynamicDispatchMethod(item); 
    } 
    catch(Exception ex) 
    { 
     logException(ex); 
    } 
}

有可能被抛出的异常的一个潜在的巨大的数字,因为这个循环是相当多的顶层我的应用程序。我项目中的代码99%落后于调度方法。我在较低层次上进行了合理的异常处理,但是错误仍然在进行中,并且在抛出异常后我不想停止批处理中的其他无关进程。

试图找出哪些异常可以在我的应用程序在其他地方扔似乎是一个艰巨的任务,它似乎是,它会更简单,以获取重要的例外的黑名单。

是否有更好的方法来组织我的应用程序来处理呢?我乐于接受建议。

+0

的[哪种类型的异常的不抓?(可能重复http://stackoverflow.com/questions/5507836/which-types-异常不可捕捉) –

回答

24

你不需要“坏”异常的列表,你应该把一切都那么糟糕默认。只抓住你能处理和恢复的东西。 CLR cannotify您未处理的异常,以便您可以适当地登录它们。吞食一切,但黑色列出的异常并不是解决您的错误的正确方法。那只会掩盖他们。阅读thisthis

醒目转移例外的目的 时,不要排除任何特殊的例外。

而是在你的catch子句创建特殊的例外列表, 你应该抓住只有对这些例外,你可以合法地 手柄。您无法处理的例外情况不应视为非特定异常处理程序中的特殊情况 。以下代码示例演示了 为了重新抛出它们而演示错误地测试了特殊的 异常。

public class BadExceptionHandlingExample2 { 
    public void DoWork() { 
     // Do some work that might throw exceptions. 
    } 
    public void MethodWithBadHandler() { 
     try { 
      DoWork(); 
     } catch (Exception e) { 
      if (e is StackOverflowException || 
       e is OutOfMemoryException) 
       throw; 
      // Handle the exception and 
      // continue executing. 
     } 
    } 
} 

很少有其他的规则:

避免被捕获非特异性异常,如 System.Exception的,System.SystemException,等等,在应用程序代码 处理错误。有些情况下,处理应用程序中的错误是可接受的,但这种情况很少见。

应用程序不应处理可能导致意外或可利用状态的异常。如果无法预测所有可能的异常原因并确保恶意代码无法利用 生成的应用程序状态,则应允许应用程序终止而不是处理异常。

当你明白为什么它会在给定的上下文中抛出时,考虑捕获特定的异常。

您应该只捕获可以从中恢复的异常。例如,对于 示例,由于试图打开 不存在的文件而导致的FileNotFoundException可以由应用程序处理,因为它可以将问题传达给用户,并允许用户指定 不同的文件名或创建文件。 生成ExecutionEngineException的文件的请求不应该被处理,因为 确定性的任何程度的 都不能确定该异常的基本原因,并且应用程序无法确保继续执行 是安全的。

Eric Lippert将所有异常分为4组:致命的,'骨头的',痛苦的,外生的。以下是我的埃里克的建议的解释:

Exc. type | What to do       | Example 
------------|-------------------------------------|------------------- 
Fatal  | nothing, let CLR handle it   | OutOfMemoryException 
------------|-------------------------------------|------------------- 
Boneheaded | fix the bug that caused exception | ArgumentNullException 
------------|-------------------------------------|------------------- 
Vexing  | fix the bug that caused exception | FormatException from 
      | (by catching exception because  | Guid constructor 
      | the framework provides no other way | (fixed in .NET 4.0 
      | way of handling). Open MS Connect | by Guid.TryParse) 
      | issue.        | 
------------|-------------------------------------|------------------- 
Exogenous | handle exception programmatically | FileNotFoundException 

这大致相当于Microsoft's分类:用法,程序出错和系统故障。 您也可以使用静态分析工具,如FxCop来执行这些规则的some

+3

您也可以处理令人头痛的异常。他们无理取闹,因为你必须在大多数情况下处理他们。 –

+0

@Eric:我已经用我对你的文章的解释更新了答案,希望我的理解正确。 – Dmitry

+2

看起来不错! ___ –

11

不要捕捉你不知道如何安全地处理任何异常。

捕获Exception是一个特别糟糕的做法,唯一更糟糕的是没有指定任何托管异常类型(因为它也会捕获非托管异常)的catch

+0

.NET 2.0将自动包装非CLS兼容异常(即,其类不从异常继承的任何异常)a当将它们呈现给符合CLS的代码中的块时,会出现RuntimeWrappedException异常;所以根本没有理由使用无参数的catch块。 –

+0

我在大多数情况下遵循这个建议,但这是一个特例。请参阅编辑。 –

1

一个更适当的设计将被支持的问题:Which exceptions应该我抓到?

如果您确实需要捕获任何和所有异常并继续前进,那么您应该同时使用AppDomain和单独的工作进程。或者将您的主机改为ASP.NET或任务调度程序,它们已经完成了有关进程隔离和重试的所有努力。

+0

感谢这个,这是需要研究的。 –

1

除非您将HandleProcessCorruptedStateExceptions属性应用于异常处理函数,否则所有'不应由用户代码处理'异常已被忽略,因此您可以安全地处理除过程破坏异常之外的任何其他内容。

1

捕获您希望代码抛出的错误。当以往任何时候都使用的API或方法,看看它会抛出什么异常,只捕获那些..你不应该做一个清单f例外,总是追赶那些..从MSDN谷歌异常处理阅读

  • 最佳实践
  • 永远赶不上机智的非特异性异常状异常