如何处理包含yield return的foreach循环中的InvalidOperationException

本文关键字:return foreach 循环 InvalidOperationException yield 包含 何处理 处理 | 更新日期: 2023-09-27 18:08:22

我有以下代码,其中我试图将ICollectionView返回的每个元素转换为不同的对象。

    public IEnumerator GetEnumerator()
    {
        foreach (TOriginal original in _collectionView)
        {
            if (!Equals(original, null))
            {
                yield return GetTranslated(original);
            }
            else
            {
                yield return default(TTranslated);
            }
        }
    }

如果_collectionView在foreach期间改变(这发生在我的测试应用程序中),那么它会抛出InvalidOperationException,但我不能在try/catch中包装foreach循环,因为VisualStudio抱怨"'yield return'语句无法出现在try/catch块中"。

如何处理异常?

如何处理包含yield return的foreach循环中的InvalidOperationException

枚举数不需要在集合被修改时保持有效。标准行为是,如果在枚举过程中修改了集合,那么下次调用MoveNext时枚举器将抛出InvalidOperationException。

我相信让InvalidOperationException传播是正确的行为。您的枚举器将具有与所有标准集合类相同的语义,因此您的类的消费者将期望这一点。

如果类的消费者需要在迭代期间更改列表,他们应该使用索引值进行循环,并在修改列表时根据需要更改索引器。

yield return不能在try...catch中,但这并不意味着您在获得要返回的值时不能捕获异常。

的例子:

object value;
try {
  value = SomeCodeThatCanBreak();
} catch (SomeException ex) {
  // you could silently skip this item:
  value = null;
}
if (value != null) {
  yield return value;
}

如果异常表明集合发生了变化,那么您应该退出循环而不是跳过项,因为您不会从枚举器中获得任何更多的项。

您必须决定对于捕获的每种异常类型应该采取什么操作。在某些情况下,静默处理异常可能是合乎逻辑的,但在大多数情况下,您应该让异常冒出来,或者抛出一个不同的异常,如果这更好地描述了问题。