关于上一篇中在foreach中Remove某一ArrayList的tiem会出错的问题,在网上搜了一下,发现这居然是一个臭名昭著的Collection问题,许多人第一次这样做的时候都中招了,现在将问题出现的原因及解决方法记录一下,确保以后不要再犯这种错误。
首先是foreach:
MSDN中的说明:foreach 语句为数组或对象集合中的每个元素重复一个嵌入语句组。foreach 语句用于循环访问集合以获取所需信息,但 不应用于更改集合内容以避免产生不可预知的副作用。
其次是ArrayList.Remove:
当你remove第i个item时,第[i + 1, count)域中所有items的索引值皆减一(Array是连续的,要满足只要有k ∈ [0, count)则Array[k]必存在),那么当你在循环下一轮用i + 1为索引访问的即是原先list中索引为i + 2的那个item,由此可知,假设0号被删除时,原1号变为新0号,原2号变为新1号。。。下一轮访问的1号就是先前的2号,而原始的1号则永远没有被访问到 。
由上面的总结可以看出,这里出现 InvalidOperationException异常的原因应该是在foreach中更改了Collection集合内容的缘故,而不是我想象中的ArrayList发生了断链,尽管在foreach循环中会少访问一个item。
问题的解决方法有好多种,除了上一篇中我的解决方法外,还可以在foreach里面用Clone,for循环,ToArray……等等多种方法。
这里我选择用反向for循环方法来解决,因为这是几种方法中最高效的。修改上篇的代码为:
反向for循环的方法非常简洁,推荐。
以上内容部分来自 http://blog.csdn.net/i_like_cpp/archive/2005/01/30/273843.aspx
首先是foreach:
MSDN中的说明:foreach 语句为数组或对象集合中的每个元素重复一个嵌入语句组。foreach 语句用于循环访问集合以获取所需信息,但 不应用于更改集合内容以避免产生不可预知的副作用。
其次是ArrayList.Remove:
当你remove第i个item时,第[i + 1, count)域中所有items的索引值皆减一(Array是连续的,要满足只要有k ∈ [0, count)则Array[k]必存在),那么当你在循环下一轮用i + 1为索引访问的即是原先list中索引为i + 2的那个item,由此可知,假设0号被删除时,原1号变为新0号,原2号变为新1号。。。下一轮访问的1号就是先前的2号,而原始的1号则永远没有被访问到 。
由上面的总结可以看出,这里出现 InvalidOperationException异常的原因应该是在foreach中更改了Collection集合内容的缘故,而不是我想象中的ArrayList发生了断链,尽管在foreach循环中会少访问一个item。
问题的解决方法有好多种,除了上一篇中我的解决方法外,还可以在foreach里面用Clone,for循环,ToArray……等等多种方法。
这里我选择用反向for循环方法来解决,因为这是几种方法中最高效的。修改上篇的代码为:
public
void
DeleteOneUser(
string
userSIPURI)
{
for (int i = userArray.Count; --i >= 0; )
{
if (((PoCContactItem)userArray[i]).GetUserSipUri() == userSIPURI)
{
userArray.RemoveAt(i);
}
}
RefeshSesonTreVw();
}
程序运行正常。
{
for (int i = userArray.Count; --i >= 0; )
{
if (((PoCContactItem)userArray[i]).GetUserSipUri() == userSIPURI)
{
userArray.RemoveAt(i);
}
}
RefeshSesonTreVw();
}
反向for循环的方法非常简洁,推荐。
以上内容部分来自 http://blog.csdn.net/i_like_cpp/archive/2005/01/30/273843.aspx