如何在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块中“。
我该如何处理异常?
答
如果集合被修改,枚举器不需要保持有效。标准的行为是,如果集合在枚举中被修改,枚举器将在下次调用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;
}
如果异常指示集合已经改变,你会退出但圈外的,而不是跳跃的项目,因为你不会得到任何更多的项目进行枚举的。
您必须决定哪种操作适合您捕获的每种异常类型。在某些情况下,默默处理异常可能是合乎逻辑的,但在大多数情况下,您应该让异常冒出来,或者抛出一个不同的异常(如果更好地描述了该问题)。
你真的需要处理异常吗?我会想象,*不处理它,让它冒泡给调用者将是最明显的行为。 – LukeH
@LukeH这是一个好点,也许我看着错误的问题 – Grokodile