今天在用Microsoft.Web.UI.WebControls.TreeView中发现了这个bug。
递归过程是加载目录树,用递归的方法一层层加载目录。
我创建一个DataTable来递归:

using System;
using Microsoft.Web.UI.WebControls;
using System.Data;

namespace TestWeb
{
    
/// <summary>
    
/// Chapters 的摘要说明。
    
/// </summary>

    public class Chapters
    
{
        
private DataTable m_chapters;
        
        
public Chapters()
        
{
            
//
            
// TODO: 在此处添加构造函数逻辑
            
//
            m_chapters = LoadData();
        }


        
public DataTable LoadData()
        
{
            DataTable dt 
= new DataTable();
            dt.Columns.Add(
new DataColumn("ChapterID",typeof(System.Int32)));
            dt.Columns.Add(
new DataColumn("ChapterName",typeof(System.String)));
            dt.Columns.Add(
new DataColumn("ParentChapter",typeof(System.Int32)));

            DataRow dr 
= dt.NewRow();
            dr[
"ChapterID"= "1";
            dr[
"ChapterName"= "root";
            dr[
"ParentChapter"= "0";
            dt.Rows.Add(dr);

            dr 
= dt.NewRow();
            dr[
"ChapterID"= "2";
            dr[
"ChapterName"= "chapter1";
            dr[
"ParentChapter"= "1";
            dt.Rows.Add(dr);

            dr 
= dt.NewRow();
            dr[
"ChapterID"= "3";
            dr[
"ChapterName"= "chapter2";
            dr[
"ParentChapter"= "1";
            dt.Rows.Add(dr);
            
            
return dt;
        }


        
/// <summary>
        
/// 获取目录结构
        
/// </summary>
        
/// <param name="nodes">TreeView的节点集</param>

        public void InitTree(TreeNodeCollection nodes)
        
{
            
//获取根结点ID            
            int rootChapterID = 1;            
            
//获取根接点数据            
            TreeNode rootNode = new TreeNode();
            rootNode.Text 
= "Root";
            rootNode.ID 
= "1";
            nodes.Add(rootNode);

            InitTree(nodes[
0].Nodes,rootChapterID);
        }

        
/// <summary>
        
/// 获取目录结构
        
/// </summary>        
        
/// <param name="nodes">TreeView的节点集</param>
        
/// <param name="parentNodeId">相对父节点Id</param>

        private void InitTree(TreeNodeCollection nodes,int parentNodeId)
        
{            
            DataView dvTree 
= m_chapters.DefaultView;       
            dvTree.RowFilter 
= "ParentChapter = " + parentNodeId;
            
if(dvTree.Count==0)
                
return;
            TreeNode tnChild;            
            
for (int i = 0; i < dvTree.Count; i++
            
{
                DataRowView drv 
= dvTree[i];
                tnChild 
= new TreeNode();
                tnChild.Text 
= drv["ChapterName"].ToString();
                tnChild.ID 
= drv["ChapterID"].ToString();                
                nodes.Add(tnChild);
                
int iParentId = Convert.ToInt32(drv["ChapterID"]);                                
                InitTree(nodes[i].Nodes, iParentId);
            }

        }

    }

}


我跟踪调试发现如下过程:
1、首先加载parentNodeID=1的所有结点,包括2个结点,其ChapterID分别为2,3。

2、可见事实上也是Count=2,如下图

3、递归第一次parentNodeID=2。

4、验证parentNodeID=2,也正确。

5、当第一次递归完成了,按道理要递归下一个parentNodeID=3了。

6、这时候确实也回到了上一级,也就是parentNodeId=1的时候。这里i的值是还没有++,++后i为1。

7、这时候bug出现了,dvTree.Count应该和第2步一样为2,可这里怎么就成了0了呢?
我猜,在实现编译器的时候,应该把dvTree保存为临时的DataView,这里把递归第一次的dvTree拿来用了。每一次递归都必须保存前一级别的DataView。事实上,却没有,DataView被丢了。上一级别的DataView和自身一级别的DataView原本就是不同的。
 

附上代码: TestWeb.rar