9

如果我有以下代码:

List<MyClass> list = GetList();
list.ForEach(i => i.SomeMethod());

假设SomeMethod()抛出异常。ForEach是继续迭代,还是就停在那里?

如果它确实终止了,有没有办法让集合中的其余项目运行它们的方法?

4

3 回答 3

14

是的,如果抛出异常,则循环退出。如果您不想要这种行为,则应将异常处理放入您的委托中。您可以轻松地为此创建一个包装器方法:

public static Action<T> SuppressExceptions<T>(Action<T> action)
{
    return item =>
    {
        try
        {
            action(item);
        }
        catch (Exception e)
        {
            // Log it, presumably
        }
    };
}

老实说,如果可能的话,我会尽量避免这种情况。捕获所有这样的异常是不愉快的。它也不会记录失败的项目或异常等。您确实需要更详细地考虑您的要求:

  • 你需要收集失败的物品吗?
  • 您需要收集异常吗?
  • 您想捕获哪些异常?

几乎可以肯定的是,创建一个使用普通foreach循环的单独方法会更干净,处理错误并在执行过程中收集错误。就我个人而言,我通常更喜欢使用foreachover-ForEach您也可能希望阅读Eric Lippert 对此的想法

于 2012-05-17T06:02:12.913 回答
4

它会抛出一个错误。您也正在重新实现foreach. 怎么样:

foreach (var item in list)
{
    try
    {
        // dangerous thing with item
    }
    catch (Exception e)
    {
        // how do you want to log this?
    }
}

这样做的好处是可以在大多数版本的 .NET 中工作,并且显然会产生副作用。当然,您可以将此代码直接放在ForEach委托中,但我只建议将其作为方法本身(而不是 lambda 函数)。


一个合理的替代方法是创建自己的ForEachWithCatch扩展来捕获所有异常并将它们发送回调用者:

public static IEnumerable<Tuple<T,Exception>> ForEachWithCatch<T>(this IEnumerable<T> items, Action<T> action)
{
    var exceptions = new List<Tuple<T,Exception>>();

    foreach(var item in items)
    {
        try
        {
            action(item);
        }
        catch(Exception e)
        {
            exceptions.Add(Tuple.Create(item, e));
        }
    }

    return exceptions;
}

这会发回每个失败的项目的可枚举及其相应的异常。

于 2012-05-17T06:03:19.010 回答
0

如果您SomeMethod已经实现了 try-catch 块,那么 foreach 将继续

void SomeMethod()
{
  try
  {
    //Some operation on i 
  }
  catch(Exception ex)
  {
  }
}

但如果不是,那么 foreach 就会中断。

这样做的一个方法是

list.ForEach(i => 
     {
         try
         {
             i.SomeMethod();
         }
         catch(Exception ex)
         {
         }
     });

但是在你的代码中有零个 try-catch 块总是好的。否则,您将永远找不到罪魁祸首。

于 2012-05-17T06:18:23.853 回答