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

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

问题描述:

我有以下代码,我试图将ICollectionView返回的每个元素都转换为不同的对象。如何在foreach循环中处理InvalidOperationException包含yield返回?

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

如果_collectionView是在foreach期间改变(这是在我的测试应用中发生的),那么这将引发InvalidOperationException,而是因为VisualStudio的抱怨““产量回报,我不能在包装一个try/catch foreach循环'语句不能出现在try/catch块中“。

我该如何处理异常?

+0

你真的需要处理异常吗?我会想象,*不处理它,让它冒泡给调用者将是最明显的行为。 – LukeH

+0

@LukeH这是一个好点,也许我看着错误的问题 – Grokodile

如果集合被修改,枚举器不需要保持有效。标准的行为是,如果集合在枚举中被修改,枚举器将在下次调用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; 
} 

如果异常指示集合已经改变,你会退出但圈外的,而不是跳跃的项目,因为你不会得到任何更多的项目进行枚举的。

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