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

时间:2011-09-12 00:39:21

标签: c# exception-handling

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

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

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

我该如何处理异常?

2 个答案:

答案 0 :(得分:3)

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

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

如果您的类的使用者需要在迭代期间更改列表,则应使用索引值循环,并在修改列表时根据需要更改索引器。

答案 1 :(得分:1)

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;
}

如果异常表明集合已经更改,那么您将退出循环而不是跳过项目,因为您将不再从枚举器中获取任何项目。

您必须决定哪种操作适合您捕获的每种异常类型。在某些情况下,静默处理异常可能是合乎逻辑的,但在大多数情况下,您应该让异常冒泡,或者如果更好地描述问题则抛出异常。