如果我有以下代码:
List<MyClass> list = GetList();
list.ForEach(i => i.SomeMethod());
假设SomeMethod()
抛出异常。ForEach
是继续迭代,还是就停在那里?
如果它确实终止了,有没有办法让集合中的其余项目运行它们的方法?
是的,如果抛出异常,则循环退出。如果您不想要这种行为,则应将异常处理放入您的委托中。您可以轻松地为此创建一个包装器方法:
public static Action<T> SuppressExceptions<T>(Action<T> action)
{
return item =>
{
try
{
action(item);
}
catch (Exception e)
{
// Log it, presumably
}
};
}
老实说,如果可能的话,我会尽量避免这种情况。捕获所有这样的异常是不愉快的。它也不会记录失败的项目或异常等。您确实需要更详细地考虑您的要求:
几乎可以肯定的是,创建一个使用普通foreach
循环的单独方法会更干净,处理错误并在执行过程中收集错误。就我个人而言,我通常更喜欢使用foreach
over-ForEach
您也可能希望阅读Eric Lippert 对此的想法。
它会抛出一个错误。您也正在重新实现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;
}
这会发回每个失败的项目的可枚举及其相应的异常。
如果您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 块总是好的。否则,您将永远找不到罪魁祸首。