您的位置:首页 > 编程语言

这段代码居然运行正常

2005-01-06 09:52 274 查看


乍一看还以为这个世界变得太快自己不认识了,再一琢磨,原来是凑巧而已,世界虽然变了点,但基本的东西还是没变的。

ArrayList test = new ArrayList();

int i;

for(i = 0;i < 20;i++)

test.Add(i);

for (i = 0;i < test.Count;i++)

if (i % 2 != 0)

test.RemoveAt(i);

for(i = 0;i < test.Count;i++)

Console.WriteLine("Array [{0}] is {1}",i,test[i]);

Console.Read();

这种类型的代码在Delphi下别说是运行结果正常,根本就是连运行都运行不了的,最后肯定会报出来一个“List index out of bounds()”这样的错误。

首先是它运行不报错,说明For循环与在delphi下是不太一样的。

Delphi代码:

for i := 0 to test.Count - 1 do

if (i mod 2) <> 0 then

test.Delete(i);

它的for循环是从一开始的时候就把初始与终止条件定好了,在循环过程中其终止条件的值是不变的(不知道如何把Delphi的CPU视图里的ASM代码拷出来,截个图算了),



看最底部的两句dec esi、jnz -$20。在最开始进入循环的时候这个esi就定了。所以说在循环体内虽然有test.Delete(i)这样的语句,但其由test.Count – 1计算得的终止条件没有变,它在最开始的时候就已经把它取出来(当然它不是取终止条件,实际上是直接把循环次数算出来给了esi的,把循环初始条件改为非0开始能看得更明白点)。所以上面这种从头开始删的方法是会报错的。

而在C#里,上面那段代码查看IL有

IL_0036: callvirt instance int32 [mscorlib]System.Collections.ArrayList::get_Count()

IL_003b: blt.s IL_0024

类似的语句。这里的for循环在执行过程中其终止条件是一直在变化的(这里for的流程决定了其for循环的强大之处;Delphi里的那个for本身的语法没有C/C#里的这么复杂,所以它的编译器作了点优化。PS:Delphi的虽然比较的简洁一点,但有时也太不方便,比如无法控制步长)。你删尽管删好了,反正它的i只到当时test.Count那个地方就停了。所以上面的代码可以运行。

至于运行正常那正好是凑巧而已了。每次RemoveAt掉一个使ArrayList后部的元素都上提的同时而i又增1,由此每次RemoveAt后for循环遍历漏掉一个元素的情况下,正好那个漏掉的元素本身是不符合条件的,反正漏掉它也无关痛痒。所以上面的运行结果看起来很正常。其实把

if (i % 2 != 0)

改为

if (i % 3 != 0)

就可以看出结果不正常了,当然if (i % 3 == 0) 这样的条件出来结果也是正常的,也是因为漏掉的元素无关痛痒的缘故。

当然即使能运行正常也不要写上面那样的代码好,只有20个元素看不太出来,如果元素一多就严重影响性能了啦。

还好世界其实并没有变。只是一个for不同而已,删东西还是从尾部开始删。

for(i = test.Count - 1;i >=0;i--)

if (i % 3 != 0)

test.RemoveAt(i);

一切恢复正常,速度也飞快。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐