将递归形式改写为迭代形式.异常处理
本文关键字:迭代 异常处理 递归 | 更新日期: 2023-09-27 18:12:00
考虑这样一个函数:
void RequestThings(List<Things> container, Connection connection, Int32 lastVersion) {
var version = lastVersion;
try {
foreach(var thing in connection.RequestThings(version)) {
container.Add(thing);
version = thing.lastVersion;
}
}
catch(Exception ex) {
RequestThings(container, connection, version + 1);
}
}
但是这个选择远不是完美的:它涉及到增加递归深度(直到堆栈溢出),以防出现(许多)异常。
我如何用迭代的方式重写这个?
我试过这样做:
var container = new List<Things>();
var version = getLastVersionFromDB();
foreach(var thing in connection.RequestThings(version)) {
try {
container.Add(thing);
}
catch(Exception ex) {
continue;
}
}
但exception
似乎没有得到处理。我该怎么做呢?
编辑。细节
-
Connection.RequestThings(Int32 startVersion)
从远程服务器请求数据。接受种子版本作为其唯一参数。可能会有阻塞/损坏的文件,您无法请求,尽管它们出现在调用Connection.RequestThings(Int32 startVersion)
返回的结果上。这段代码抛出异常 - 不知道为什么,但内部
try/catch
在我的iterative
的例子没有捕捉到异常。
一般来说,为所有异常使用catch
子句是一个坏主意。考虑只捕获特定的异常类型,以确保不会出现意外错误。
另外,如果一开始就出现了堆栈溢出,这表明您可能做错了什么。例如,如果将无效的version
号传递给此方法,并且没有具有更大版本号的文档可用,会发生什么情况?此方法将永远运行,没有机会优雅地取消它。特别是因为你似乎正在从数据库中获得"最后版本";如果此操作失败,则可以非常确定不存在更高版本。
话虽如此,您可以通过创建一个"无限"循环来简化该方法,然后在成功时使用return
退出该方法:
void RequestThings(List<Things> container, Connection conn, int version)
{
while (true)
{
try
{
foreach (var thing in connection.RequestThings(version))
{
container.Add(thing);
version = thing.lastVersion;
}
return;
}
catch (Exception ex)
{
Log.Error(ex);
version++;
}
}
}
一个稍微好一点的方法可能是确保你真的获得了成功的整个列表,或者什么都没有。如果在迭代过程中发生异常,您现在编写代码的方式可能会导致container
被多次填充。
List<Things> RequestThings(Connection conn, int version)
{
while (true)
{
try
{
// this will either create an entire list,
// or fail completely
return connection.RequestThings(version).ToList();
}
catch (Exception ex)
{
Log.Error(ex);
version++;
}
}
}