讨教各位高手,这个问题思考很久,也没有想明白。需求:实现如下面所示的层级(无法上传图片,原谅本人手打组织机构)
公司总部(父节点)
领导层(子节点)
人力资源部(子节点)
通过逐行跟踪发现,生成该组织机构树的时候,领导层下面没有其他机构的时候,结束以领导层为父节点寻找其子节点的foreach循环后,问题就来了(1)程序为什么走到81行最后一个大括号后又直接返回第78行的AddTree函数,(2)接下来还不进入AddTree函数内部,走完第79,80行大括号后,直接又从foreach中开始对将人力资源部添加到父节点公司总部的过程。
公司总部(父节点)
领导层(子节点)
人力资源部(子节点)
通过逐行跟踪发现,生成该组织机构树的时候,领导层下面没有其他机构的时候,结束以领导层为父节点寻找其子节点的foreach循环后,问题就来了(1)程序为什么走到81行最后一个大括号后又直接返回第78行的AddTree函数,(2)接下来还不进入AddTree函数内部,走完第79,80行大括号后,直接又从foreach中开始对将人力资源部添加到父节点公司总部的过程。
/// <summary> /// 将数据库中的记录添加到树中(递归) /// </summary> AddTree(dtDept, "a", null, tnRoot, "父机构编码", "机构编码", "机构名称", 1, srr); /// <param name="dtDept">部门表</param> /// <param name="initColumnName">节点的Code(初始化为"null")</param> /// <param name="tnNode">父节点的code(初始化设为null即可,原因是根节点的code为null)</param> /// <param name="root">父节点</param> /// <param name="strItemPcode">父节点名(数据库中的字段名)</param> /// <param name="strItemcode">节点名(数据库中的字段名)</param> /// <param name="strItemText">显示的文本(数据库中的字段名)</param> /// <param name="degree">控制树展开的层数</param> public void AddTree(DataTable dtDept, string initColumnName, TreeNode tnNode, TreeNode root, string strItemPcode, string strItemcode, string strItemText, int degree,string rr) { DataView dvTree = new DataView(dtDept); dvTree.RowFilter = "[" + strItemPcode + "] = "" + initColumnName + """;//进行行过滤 dvTree.Sort = "报表序号"; foreach (DataRowView Row in dvTree) { TreeNode Node = new TreeNode(); if (tnNode == null) { Node.Text = Row[strItemText].ToString(); Node.Tag = Row[strItemcode].ToString(); Node.ImageKey = Row["组织层级"].ToString(); Node.SelectedImageKey = Row["机关属性"].ToString(); Node.StateImageKey = Row["报表序号"].ToString(); Node.ToolTipText = Row["机构状态"].ToString(); if (Row["机构状态"].ToString() == "已撤销") { Node.ForeColor = Color.Red; } root.Nodes.Add(Node); if (degree > 0) { Node.Parent.Expand(); } AddTree(dtDept, Row[strItemcode].ToString(), Node, root, strItemPcode, strItemcode, strItemText, --degree, rr);//递归 } else { //组织机构树中显示班长名称 if (Row["机关属性"].ToString() == "班组") { if (Row["负责人"].ToString().Length > 0) { Node.Text = Row[strItemText].ToString() + "(" + Row["负责人"].ToString() + ")"; } else { Node.Text = Row[strItemText].ToString() + "(缺编)"; } } else { Node.Text = Row[strItemText].ToString(); } //Node.Text = Row[strItemText].ToString(); Node.Tag = Row[strItemcode].ToString();//设主键,这是数据库中的 Node.ImageKey = Row["组织层级"].ToString(); Node.SelectedImageKey = Row["机关属性"].ToString(); Node.StateImageKey = Row["报表序号"].ToString(); Node.ToolTipText = Row["机构状态"].ToString(); if (Row["机构状态"].ToString() == "已撤销") { Node.ForeColor = Color.Red; } tnNode.Nodes.Add(Node); if (degree > 0) { Node.Parent.Expand(); } AddTree(dtDept, Row[strItemcode].ToString(), Node, root, strItemPcode, strItemcode, strItemText, --degree, rr); } } }
解决方案
10
纠结某个编程语言、某段代码,是比较底层的模式,它依赖于你对数据结构、算法的知识而表现不同。
例如你这里采用了“左递归深度优先算法”来加载数据,那么在加载完第一个领导,假设它没有下属组织机构(也就是tnNode == null条件成立),那么自然程序跟踪调试指针就回到了foreach来遍历下一个领导的那条居于,而不会回到任何AddTree语句;假如是它下属有一个组织结构(人力资源部),那么加载完人力资源部之后程序跟踪调试指针自然就回到了加载这个人力资源部的AddTable语句。
也许你还是看不懂本人这里的描述。本人要告诉你的是,要看数据,不要死盯着代码。你每一条代码的语法都学过,但是就是不懂程序流程,这就好像是死记硬背了字典之后一个人也不能真正立刻学会写畅销小说,用再好的金笔的人也不一定能成为莫言,同样的道理。你要调试的是程序锁操作数据,不要眼里只有程序代码。那样就学“死”了。
例如你这里采用了“左递归深度优先算法”来加载数据,那么在加载完第一个领导,假设它没有下属组织机构(也就是tnNode == null条件成立),那么自然程序跟踪调试指针就回到了foreach来遍历下一个领导的那条居于,而不会回到任何AddTree语句;假如是它下属有一个组织结构(人力资源部),那么加载完人力资源部之后程序跟踪调试指针自然就回到了加载这个人力资源部的AddTable语句。
也许你还是看不懂本人这里的描述。本人要告诉你的是,要看数据,不要死盯着代码。你每一条代码的语法都学过,但是就是不懂程序流程,这就好像是死记硬背了字典之后一个人也不能真正立刻学会写畅销小说,用再好的金笔的人也不一定能成为莫言,同样的道理。你要调试的是程序锁操作数据,不要眼里只有程序代码。那样就学“死”了。
10
递归在调试时,会由于重复调用某个方法,而看起来断点很混乱。
其实说白了,就是第一次进入递归,调用方法A,还没结束,但是第二次递归已经来了,又调用了方法A,所以断点会跳来跳去。
可是你心里应该清楚,这是递归的第二次结果进来了。
其实说白了,就是第一次进入递归,调用方法A,还没结束,但是第二次递归已经来了,又调用了方法A,所以断点会跳来跳去。
可是你心里应该清楚,这是递归的第二次结果进来了。