在.Net / C#中抛出多个exception

在我工作的应用程序中,任何业务逻辑错误都会导致引发exception,并且调用代码处理exception。 这种模式在整个应用程序中使用,运作良好。

我有一种情况,我将试图从业务层内执行一些业务任务。 对此的要求是一个任务的失败不应该导致该过程终止。 其他任务仍然应该能够执行。 换句话说,这不是一个primefaces操作。 我遇到的问题是,在操作结束时,我希望通知抛出exception的调用代码,确实发生了exception。 考虑下面的伪代码片段:

function DoTasks(MyTask[] taskList) { foreach(MyTask task in taskList) { try { DoTask(task); } catch(Exception ex) { log.add(ex); } } //I want to throw something here if any exception occurred } 

我扔什么? 我以前在职业生涯中遇到过这种模式。 在过去,我保存了所有exception的列表,然后抛出一个包含所有捕获的exception的exception。 这似乎不是最优雅的方法。 从每个例外中保留尽可能多的细节以呈现给调用代码是很重要的。

思考?


编辑:解决scheme必须使用.Net 3.5编写。 我不能使用任何beta库,或者如Bradley Grainger所提到的.Net 4.0中的AggregateException(下面),这将是集合exception抛出的一个很好的解决scheme。

.NET的任务并行库扩展 ( 将成为.NET 4.0的一部分 )遵循其他答案中提出的模式:收集所有抛入AggregateException类的exception。

通过总是抛出相同的types(无论是有一个例外还是很多),处理exception的调用代码更容易编写。

在.NET 4.0 CTP中, AggregateException有一个公共构造函数(它接受IEnumerable<Exception> ); 它可能是您的应用程序的一个不错的select。

如果您的目标是.NET 3.5,请考虑克隆您自己的代码中需要的System.Threading.AggregateException类的某些部分,例如一些构造函数和InnerExceptions属性。 (你可以把你的克隆放到你的程序集里面的System.Threading命名空间中,如果你公开地公开地暴露它,这可能会引起混淆,但是稍后会更容易升级到4.0。)当.NET 4.0发布时,你应该能够“升级“为Frameworktypes,方法是从项目中删除包含您的克隆的源文件,将项目更改为目标新的框架版本,然后重新构build。 当然,如果你这样做的话,在微软发布新的CTP时,你需要仔细地跟踪这个类的变化,这样你的代码就不会变得不兼容。 (例如,这看起来像是一个有用的通用类,它们可以将它从System.Threading移动到System 。)在最坏的情况下,您可以重命名types并将其移回到您自己的名称空间中(这是非常容易与大多数重构工具)。

我脑海中的两种方法是创build一个自定义的exception,并将这个exception添加到这个类中,然后抛出:

 public class TaskExceptionList : Exception { public List<Exception> TaskExceptions { get; set; } public TaskExceptionList() { TaskExceptions = new List<Exception>(); } } public void DoTasks(MyTask[] taskList) { TaskExceptionList log = new TaskExceptionList(); foreach (MyTask task in taskList) { try { DoTask(task); } catch (Exception ex) { log.TaskExceptions.Add(ex); } } if (log.TaskExceptions.Count > 0) { throw log; } } 

或者如果任务失败并返回“列表”variables,则返回true或false。

  public bool TryDoTasks(MyTask[] taskList, out List<Exception> exceptions) { exceptions = new List<Exception>(); foreach (MyTask task in taskList) { try { DoTask(task); } catch (Exception ex) { exceptions.Add(ex); } } if (exceptions.Count > 0) { return false; } else { exceptions = null; return true; } } 

您可以创build一个自定义exception,并拥有一组exception。 然后,在您的Catch块中,只需将其添加到该集合。 在你的过程结束时,检查Exception count是否> 0,然后抛出你的自定义exception。

你可能想使用BackgroundWorker来为你做这个。 它会在完成时自动捕捉和呈现任何exception,然后您可以抛出,logging或执行任何操作。 而且,你可以得到multithreading的好处。

BackgroundWorker是委托的asynchronous编程模型的一个很好的包装。

这里没有超优雅的解决scheme,但有一些想法:

  • 将error handling函数作为parameter passing给DoTasks,以便用户可以决定是否继续
  • 使用跟踪logging发生的错误
  • 在exception包的消息中连接来自其他exception的消息