首先,我們建立一個VS WinForm項目,建立一個表單,表單中有一個TreeView和Button控制項,TreeView中添加10個Nodes,Name分別為n0,n1,n2....,Text分別為node0,node1,node2......,Button的功能是將TreeView中的Nodes清空,
(一)
圖(一)
然後,在Button的Click事件中添加清除Nodes的代碼,且都將用迴圈來實現此功能,分別用for,foreach,while迴圈來實現:
① for迴圈
for (int i = 0; i < trvCirTest.Nodes.Count; i++)
{
trvCirTest.Nodes.Remove(trvCirTest.Nodes[i]);
}
② foreach迴圈
foreach (TreeNode node in trvCirTest.Nodes)
{
trvCirTest.Nodes.Remove(node);
}
③ while迴圈
int i = 0;
while (trvCirTest.Nodes.Count > 0)
{
trvCirTest.Nodes.Remove(trvCirTest.Nodes[i]);
i++;
}
迴圈體均用try{}catch{}模組捕捉異常,則分別點擊按鈕後,出現不同的結果:
① for迴圈
沒有異常拋出,但每次按鈕點擊都只能清空Nodes的一半
② foreach迴圈
每次按鈕點擊都只能清空Nodes的一半,且拋出(二)的異常
圖(二)
③ while迴圈
每次按鈕點擊都只能清空Nodes的一半,且拋出(三)的異常
圖(三)
按照普通思維,程式遍曆到第一個Node,將第一個Node刪除,遍曆到第二個Node的時候,將第二個Node刪除.....,應該可以將全部Node刪除的,為什麼會這樣呢,甚至拋出異常?
現在,我們通過斷點跟蹤的方式,可以發現:
① for迴圈
當i=0時,trvCirTest.Nodes.Count值為10,
當i=1時,trvCirTest.Nodes.Count值為9,
當i=2時,trvCirTest.Nodes.Count值為8,
......
當i=4時,trvCirTest.Nodes.Count值為為6,
當i=5時,trvCirTest.Nodes.Count值為為5,5<5?false,跳出迴圈。
② foreach迴圈
遍曆第一次,Remove node0,
遍曆第二次,Remove node2,
遍曆第三次,Remove node4,
......
遍曆第五次,應該Remove node10,此時,node10不存在,拋出異常。
③ while迴圈
情況與for迴圈時類似,但while迴圈是不會跳出的,當迴圈到第5個的時候,trvCirTest.Count的值為5,trvCirTest.Remove(trvCirTest.Nodes[5])時,拋出異常。
分析總結:
從上面的調試看出,迴圈指標是採用後挪式的,每迴圈一次,指標都向後移動一位。然而,當元素被刪除時,指標並不會因為元素的改變而停止不前,更不可能向後退;而元素組合卻像沙漏,下面的沙子漏出後,上面的沙子立即會填充漏出的沙子原來佔有的空間。這個有點像注射器,元素好比注射器中的液體,迴圈指標指向刻度,指標按照刻度從小到大增加,卻不會因為液體的減少而停止減小或減小。
最後,建議MS考慮這個問題,能否實施監測到這些元素的變化而改變指標呢?當然,這個問題只是針對當前程式或類似程式,我並不知道如果MS做這樣的改變是否會引起其他的問題,僅當參考!
另外,附上解決方案,其實也很簡單:
① for迴圈
for (int i = 0; i < trvCirTest.Nodes.Count; i++)
{
trvCirTest.Nodes.Remove(trvCirTest.Nodes[0]);
② foreach迴圈
foreach (TreeNode node in trvCirTest.Nodes)
{
trvCirTest.Nodes.Remove(trvCirTest.Nodes[0]);
}
③ while迴圈
while (trvCirTest.Nodes.Count > 0)
{
trvCirTest.Nodes.Remove(trvCirTest.Nodes[0]);
}