使用 yield 时,在 try/catch 中包装对迭代器的调用

本文关键字:包装 迭代器 调用 catch yield try 使用 | 更新日期: 2023-09-27 18:34:15

我需要在我作为迭代器实现的方法中做一些繁重的、有点脆弱的逻辑(使用 yield):

public IEnumerable<Things> GetMoreThings() {
    while (goodStuffHappens()) {
        Things moreThingsIWant = TemptFateAgain();
        if (moreThingsIWant.Any())
            yield return moreThingsIWant;
    }
}

在调用方法中,我需要将调用包装在 try/catchGetMoreThingsyield return结果:

try {
    foreach (Things thing in Helpful.GetMoreThings())
        yield return thing;
}
catch (Exception e) {
    //crash, burn
}

发起者会立即意识到这是不可能的 - try/catch块内没有收益这样的东西(只有 try/finally )。

有什么建议吗?

使用 yield 时,在 try/catch 中包装对迭代器的调用

这里的两个答案都是正确的。这个没有内置的快捷方式,您需要在while而不是for循环中梳理迭代器,以便在调用Enumerator.MoveNext()和使用Enumerator.Current之间分开。

IEnumerator<Things> iterator = Helpful.GetMoreThings.GetEnumerator();
bool more = true;
while (more) {
    try {
        more = iterator.MoveNext();
    }
    catch (Exception e) {
        //crash, burn
    }
    if (more)
        yield return iterator.Current;
}

Helpful.GetMoreThings()调用和枚举与yield分开:

try {
    var results = Helpful.GetMoreThings().ToList();
}
catch (Exception e) {
    //crash, burn
}
foreach (Things thing in results)
    yield return thing;

类似的东西。

如果你需要这个懒惰,代码会变得非常讨厌。您不能再使用 foreach .您需要手动编写迭代循环,代码大小会爆炸到20行难以辨认的混乱。我知道,因为我昨天做了这件事。

您可以使用 Ix.Net 中的 Catch() 扩展方法,或者只复制其 Apache 许可的源代码。代码可能如下所示:

return Helpful.GetMoreThings().Catch((Exception e) =>
{
    // crash, burn
    return null;
}