遍历ArrayList易犯错误

遍历ArrayList易犯错误

场景:

将ArrayList中符合条件的记录删掉,第一时间写出的程序如下:

foreach (string aStr in aList)
{
if (aStr.Equals(textBox1.Text))
{
aList.Remove(aStr);
}
}
似乎没有错误,编译也通过的,但运行时如果真的遇到符合条件的数据,则会抛出错误:

按此在新窗口打开图片
简单的解决办法是如何呢?这时用Clone方法最好不过了,用如下代码:

ArrayList bList = (ArrayList)aList.Clone();
foreach (string aStr in bList)
{
if (aStr.Equals(textBox1.Text))
{
aList.Remove(aStr);
}
}

似乎集合类型都会有这样的问题的。

posted on 2004-09-08 13:53 风前絮~~ 阅读(1047) 评论(25) 编辑 收藏

评论

re: 遍历ArrayList易犯错误

用for就可以避免这样的问题,而且for的执行效率还高过foreach
2004-09-08 14:10 | 什么都不知道

re: 遍历ArrayList易犯错误

啊,你.....你居然...居然敢用foreach来reomove,这是臭名昭著的Collection问题.....
2004-09-08 14:24 | 寒枫天伤

re: 遍历ArrayList易犯错误

我一般是用
foreach(object item in al.ToArray())
..
或者是 in new ArrayList(somecollection).

2004-09-08 14:55 | Lostinet

re: 遍历ArrayList易犯错误

好象是有一个浅表拷贝的方法。
最好是用哪个,不要用Clone
2004-09-08 15:11 | hyifeng

re: 遍历ArrayList易犯错误

用for语句反向遍历即可
2004-09-08 16:07 | feilng

re: 遍历ArrayList易犯错误

我也犯过这样的错误,呵呵
2004-09-08 16:10 | cure

re: 遍历ArrayList易犯错误

To 什么都不知道:
for的方法也可以啊,代码如下?
for (int i=0;i

  1<alist.count;i++) #="" (alist[i].equals(textbox1.text))="" (int="" --i="" 16:12="" 16:18="" 16:23="" 17:56="" 2004-09-08="" alist.removeat(i);="" clone和toarray至少增加了处理量="" dali="" fantasysoft="" feilng:="" for="" hyifeng:="" i="aList.Count;" if="" lostinet="" re:="" to="" |="" 你的方法也不错啊="" 删除的代码如下:="" 反向遍历?有什么好处啊?大致如何实现呢?="" 受不了你们了,竟然。。。。竟然这种低级的错误都犯!!!!一个还不要紧,竟然是一群!!!晕~="" 如何可以获得比较的数据?="" 对于arraylist,clone已经是一个浅表副本了。你说的是memberwiseclone吗?="" 对于for的代码,应该增加一个条件分支,调用了removeat方法的话,index不能够增加。也就是说循环递增语句不应该写在for的括号里面。="" 我也有过,for应该是最安全的,而且简单易懂="" 看来这种处理已经有三种方法了,foreach里面用clone,for循环,toarray,不知道那种比较好呢?="" 遍历arraylist易犯错误="" 风前絮~~="" :="">=0;)   
  2if (aList[i].Equals(textBox1.Text))   
  3aList.RemoveAt(i);   
  42004-09-08 18:54 | 老翅    
  5# re: 遍历ArrayList易犯错误   
  6呵呵~   
  72004-09-08 19:20 | hBifTs   
  8# re: 遍历ArrayList易犯错误   
  9To 老翅:   
 10  
 11哈哈~~ 话也不能这么说了,编程那里会没有错误呢?要不也不会有BUG了。   
 12  
 13感谢你贴的代码,我试过了,没有问题,可以说是for的一种方法。   
 14  
 15To FantasySoft :   
 16  
 17我那个for的代码也是通过了的,可以达到效果,请指明我代码错误,感谢!   
 182004-09-08 19:58 | 风前絮~~   
 19# re: 遍历ArrayList易犯错误   
 20To 风前絮~~ :代码本身语法没有错,只是逻辑上有问题而已。因为RemoveAt方法会改变Count方法的返回值,就造成了不是每个元素都被遍历到。这也是feilng和老翅提出反向遍历的原因。   
 21请看以下代码:   
 22using System.Collections;   
 23using System;   
 24class Test   
 25{   
 26public static void Main()   
 27{   
 28ArrayList test = new ArrayList();   
 29for(int i=0; i &lt; 3; i++)   
 30test.Add("test");   
 31test.Add("testAgain");   
 32test.Add("testAgain");   
 33for(int i=0; i &lt; test.Count; i++)   
 34{   
 35if (test[i].Equals("test"))   
 36test.RemoveAt(i);   
 37}   
 38for(int i = 0; i &lt; test.Count;i++)   
 39Console.WriteLine(test[i]);   
 40}   
 41}   
 42  
 43test这个ArrayList里面的"test"是不是应该都被remove掉呢?事实上如果这样写,还是会剩下一个的。   
 442004-09-09 02:22 | FantasySoft   
 45# re: 遍历ArrayList易犯错误   
 46To FantasySoft:   
 47  
 48十分感谢! 原来的代码因为每个不相同的,因此没有发现这个问题。   
 49仔细想了下,确实如你所说: Count变了,使得index=0的被漏掉了。   
 50  
 51看来for的方法只有反向遍历了。   
 52  
 53有空用ILDASM看了下三种不同方法生成的代码,比较对应函数,发现用的堆栈最大值一样,代码长度不同,for的最短,ToArray()居中,Clone最多。   
 54  
 55正向for的方法要加个语句就可以了,但看起来比反向臃肿了:   
 56for (int i=0;i&lt;aList.Count;i++)   
 57if (aList[i].Equals(textBox1.Text))   
 58{   
 59aList.RemoveAt(i);   
 60i--;   
 61}   
 622004-09-09 09:18 | 风前絮~~   
 63# re: 遍历ArrayList易犯错误   
 64To 风前絮~~ :可以这样写   
 65for (int i=0;i&lt;aList.Count;)   
 66if (aList[i].Equals(textBox1.Text))   
 67{   
 68aList.RemoveAt(i);   
 69}   
 70else   
 71i++;   
 72这样写是不是就更清晰了呢?for的递增语句不一定要写到for的括号里面的。   
 73  
 742004-09-09 10:24 | Fantasysoft   
 75# re: 遍历ArrayList易犯错误   
 76对呀,也是个方法! ^_^   
 772004-09-09 10:36 | 风前絮~~   
 78# re: 遍历ArrayList易犯错误   
 79恕我直言,看到楼主你的“仔细想了下,确实如你所说:Count变了,使得index=0的被漏掉了。”这句话,感觉你并没有真正理解为什么会产生楼顶的问题   
 80  
 81被遗漏的并不是原list的0号item,而是1号item   
 82  
 83为什么呢?因为当你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号则永远没有被访问到   
 84  
 85明白了这个自然可以得出正确的迭代方法,正序时需注意索引和可能变化的终止条件,倒序时则简单些   
 862004-09-09 14:44 | 问题男   
 87# re: 遍历ArrayList易犯错误   
 88To 问题男:   
 89  
 90Oh~~ Sorry,估计是我的表达有问题。   
 91index=0是Count变了后的,它原来的index确实=1,正如你所说的。   
 92  
 93感谢指正!   
 942004-09-09 15:16 | 风前絮~~   
 95# re: 遍历ArrayList易犯错误   
 96re: 遍历ArrayList易犯错误   
 97用for语句反向遍历即可   
 982004-09-08 16:07 | feilng   
 99  
100完全同意,我觉得这是最好的办法了   
101p.s.这种事情,没有出过错的人第一次都会写错的,哈哈   
1022004-09-09 16:56 | myrat   
103# re: 遍历ArrayList易犯错误   
104看看这段代码,会有什么结果?   
105  
106int[] myarray = {1,2,3};   
107  
108foreach(int num in myarray){   
109num++;   
110}   
1112004-09-09 17:21 | juqiang   
112# re: 遍历ArrayList易犯错误   
113To juqing:   
114  
115有趣啊   
116应该是不行的   
117  
118\--------------------------------------------------------------------------------   
119MSDN中的说明:   
120foreach 语句为数组或对象集合中的每个元素重复一个嵌入语句组。foreach 语句用于循环访问集合以获取所需信息,但不应用于更改集合内容以避免产生不可预知的副作用。   
121  
122\--------------------------------------------------------------------------------   
123  
124num++ 等价于 num = num + 1,修改内容了。   
125编译报错:   
126...(201): 无法分配到“num”,因为它是只读的   
127  
1282004-09-09 17:33 | 风前絮~~   
129# 遍历ArrayList易犯错误[TrackBack]   
130Ping Back来自:blog.csdn.net   
131windsails引用了该文章,地址:  http://blog.csdn.net/windsails/archive/2004/09/10/100331.aspx    
1322004-09-10 13:21 | windsails   
133# re: 遍历ArrayList易犯错误   
134为什么要反向?   
135  
136int i =0;   
137while( i&lt;aList.Count)   
138{   
139if (aList[i].Equals(textBox1.Text))   
140{   
141aList.RemoveAt(i)   
142continue;   
143}   
144i++;   
145}   
146  
1472004-10-20 21:29 | 大力水手   
148# re: 遍历ArrayList易犯错误   
149反向简单且效率高啊,aList.Count只在初始化时用一次,其他情况要每次都用啊。虽说aList.Count也是变量,但从机器码的角度来说,间接地址引用还是要花比寄存器引用多很多的时间的。   
1502004-12-09 12:45 | 无名</alist.count;i++)>
Published At
Categories with Web编程
Tagged with
comments powered by Disqus