在循环中处理多个异常

7

在我的代码中,一个方法在循环中被反复调用,就像这样:

foreach (var file in files)
{
    SomeMethod(file);
}

该方法可能会抛出异常,但我不希望代码在第一个异常后退出循环。
此外,上面的代码是从 Web API 控制器中调用的,因此我需要一种方法将所有异常信息传递回控制器,在那里处理异常(记录异常并返回错误响应给客户端)。
到目前为止,我已经捕获并存储了所有异常在列表中。
var errors = new List<Exception>();

foreach (var file in files)
{
    try
    {
        SomeMethod(file);
    }
    catch(Exception ex)
    {
        errors.Add(ex);
    }
}

考虑到不能将列表中的所有错误都重新抛出,那么将异常信息返回给控制器的最佳方法是什么?


你可以使用字符串构建器将循环本身的信息与异常中的消息连接起来,然后重新抛出。 - Giorgi Nakeuri
如果有不同的异常类型,这种方法就行不通了,对吧? - elolos
2个回答

5

使用AggregateException

您可以将List<Exception>传递给其构造函数并抛出该异常。

在循环结束时执行以下操作:

AggregateException aggregateEx = new AggregateException(errors);
throw aggregateEx;

(或返回AggregateException

我正准备写一个自己版本的AggregateException的答案...应该先检查一下库。 - RoadieRich
谢谢,抛出AggregateException可能是我正在寻找的,我会尝试并让您知道。我不知道返回异常是否是良好的实践。此外,当只有一个异常时我该怎么办? - elolos
通常情况下,返回异常并不是一个好的做法(虽然我不确定你的情况)。无论你想要返回单个异常还是多个异常,都可以使用AggregateException。但是,如果你总是期望一个单一的异常或者想要在第一个异常的情况下退出,则不需要使用AggregateException - Habib
谢谢@Habib。我已经添加了一个包含解决方案的答案,但是我会接受你的答案,因为它非常有帮助。 - elolos

1

根据Habib的建议,我实现了一个解决方案,它还处理了只有一个异常情况的情况。这样就不会出现不必要的嵌套异常。

if (errors.Any())
{
    if (errors.Count > 1)
    {
        throw new AggregateException("Multiple errors. See InnerExceptions for more details",errors);
    }
    else
    {
        ExceptionDispatchInfo.Capture(errors[0]).Throw();
    }
}

仅通过调用 throw errors[0]; 重新抛出单个异常应该被避免,因为它不会保留原始异常的堆栈跟踪。


你确定你发布的代码保留了堆栈跟踪吗?我真的很怀疑。你需要在catch块中调用Capture。 - ciuly
我不确定,因为我写这段代码已经超过4年了。你试过了吗? - elolos
1
我做了。为了能够实际捕获所有所需的信息以进行适当的抛出(),需要在catch块中调用ExceptionDispatchInfo.Capture。 因此,您需要一个ExceptionDispatchInfo列表,而不是异常列表。 - ciuly

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接