C# 如何搜索自定义类的所有嵌套子类?

C# 如何搜索自定义类的所有嵌套子类?,c#,C#,我在数据库中有一个表,如下所示: | id | parentID | name | |----------+----------+-------------| |ABCD-12345| | Top | |----------+----------+-------------| |ABCD-23456|ABCD-12345| Middle | |----------+----------+-------------| |ABCD

我在数据库中有一个表,如下所示:

|    id    | parentID |    name     |
|----------+----------+-------------|
|ABCD-12345|          |    Top      |
|----------+----------+-------------|
|ABCD-23456|ABCD-12345|   Middle    |
|----------+----------+-------------|
|ABCD-34567|ABCD-23456|   Bottom    |
|----------+----------+-------------|
|ABCD-45678|ABCD-23456|   Bottom    |
等等——基本上是N深度的层次结构。我把它放到了一个数据表中

static List<DataTableData> GetDataTableData()
{
    var data = new List<DataTableData>
    {
        new DataTableData() { Id = "23456", ParentID = "12345", Name = "Middle" },
        new DataTableData() { Id = "55555", ParentID = "12345", Name = "Middle" },
        new DataTableData() { Id = "34567", ParentID = "23456", Name = "Bottom" },
        new DataTableData() { Id = "12345", ParentID = string.Empty, Name = "Top" },
        new DataTableData() { Id = "45678", ParentID = "23456", Name = "Bottom" },
        new DataTableData() { Id = "66666", ParentID = "55555", Name = "Bottom" }
    };
    return data;
}
我构建了以下类来保存这些数据:

public class TreeNode
{
    public string id { get; set; }
    public string name { get; set; }
    public string parentID { get; set; }
    public List<TreeNode> children { get; set; }
}
它获取一个超出范围的异常,因为我在索引0处有一个根,所以在第二次运行时(当
currNode
为1时),它会中断。我需要遍历到
treeList[0]。Children[int]
,然后是
treeList[0]。Children[int]。Children[int]
等等


那么我如何实现这个目标呢?

首先,为了方便起见,我将修改
TreeNode
类。这不是必须的,只是一个很好的选择。另外,我将假设在您的数据表中,您已经完成了错误检查,并且只有一个节点具有
ParentId=“”

这就是您的
Main()
的外观:

static void Main(string[] args)
{
    var treeNodes = new List<TreeNode>();

    var dataTable = GetDataTableData();
    foreach (var data in dataTable)
    {
        treeNodes.Add(new TreeNode() { Id = data.Id, Name = data.Name, ParentID = data.ParentID });
    }

    var root = BuildTree(treeNodes);

    Console.ReadLine();
}

BuildTree()
分解
节点
列表中已包含与数据表中的数据对应的所有节点。
BuildTree()
只会创建父子关系并填充每个对象的
子对象列表

所以我遍历列表,看看列表中的其他元素应该是它的子元素。当您遍历列表时,您已经创建了所有的父子关系。最后,我选择根节点(ParentId为空的
ParentId
)并返回它


编辑 这里有一个简单的方法来打印和验证您的树

static void PrintTree(TreeNode node, int indents)
{
    for (int tab = 0; tab < indents; tab++)
    {
        Console.Write("\t");
    }

    Console.WriteLine("{0} - {1}", node.Id, node.Name);
    if (node.Children != null && node.Children.Count > 0)
    {
        indents++;
        foreach (var child in node.Children)
        {
            PrintTree(child, indents);
        }
    }
}
静态void打印树(TreeNode节点,int缩进)
{
对于(int-tab=0;tab0)
{
缩进++;
foreach(node.Children中的变量child)
{
打印树(子级,缩进);
}
}
}
我的输出如下所示:

|    id    | parentID |    name     |
|----------+----------+-------------|
|ABCD-12345|          |    Top      |
|----------+----------+-------------|
|ABCD-23456|ABCD-12345|   Middle    |
|----------+----------+-------------|
|ABCD-34567|ABCD-23456|   Bottom    |
|----------+----------+-------------|
|ABCD-45678|ABCD-23456|   Bottom    |

首先,为了方便起见,我将修改
TreeNode
类。这不是必须的,只是一个很好的选择。另外,我将假设在您的数据表中,您已经完成了错误检查,并且只有一个节点具有
ParentId=“”

这就是您的
Main()
的外观:

static void Main(string[] args)
{
    var treeNodes = new List<TreeNode>();

    var dataTable = GetDataTableData();
    foreach (var data in dataTable)
    {
        treeNodes.Add(new TreeNode() { Id = data.Id, Name = data.Name, ParentID = data.ParentID });
    }

    var root = BuildTree(treeNodes);

    Console.ReadLine();
}

BuildTree()
分解
节点
列表中已包含与数据表中的数据对应的所有节点。
BuildTree()
只会创建父子关系并填充每个对象的
子对象列表

所以我遍历列表,看看列表中的其他元素应该是它的子元素。当您遍历列表时,您已经创建了所有的父子关系。最后,我选择根节点(ParentId为空的
ParentId
)并返回它


编辑 这里有一个简单的方法来打印和验证您的树

static void PrintTree(TreeNode node, int indents)
{
    for (int tab = 0; tab < indents; tab++)
    {
        Console.Write("\t");
    }

    Console.WriteLine("{0} - {1}", node.Id, node.Name);
    if (node.Children != null && node.Children.Count > 0)
    {
        indents++;
        foreach (var child in node.Children)
        {
            PrintTree(child, indents);
        }
    }
}
静态void打印树(TreeNode节点,int缩进)
{
对于(int-tab=0;tab0)
{
缩进++;
foreach(node.Children中的变量child)
{
打印树(子级,缩进);
}
}
}
我的输出如下所示:

|    id    | parentID |    name     |
|----------+----------+-------------|
|ABCD-12345|          |    Top      |
|----------+----------+-------------|
|ABCD-23456|ABCD-12345|   Middle    |
|----------+----------+-------------|
|ABCD-34567|ABCD-23456|   Bottom    |
|----------+----------+-------------|
|ABCD-45678|ABCD-23456|   Bottom    |

如果要构建类结构,则需要使用递归方法的类。如果它变得太大,不确定它的效率会有多高。从树的顶部执行该方法

public class TreeNode  
{
    public string id { get; set; }
    public string name { get; set; }
    public string parentID { get; set; }
    public List<TreeNode> children { get; set; }

    public TreeNode() {
        children = new List<TreeNode>();
    }

    public TreeNode FindParentWithID(string ID)
    {
        TreeNode ParentWithID = null;

        //check my parentID if i am the one being looked for then return
        if (id == ID) return this;

        //search children
        foreach (TreeNode treeNode in children)
        {
            ParentWithID = treeNode.FindParentWithID(ID);

            if (ParentWithID != null)
            {
                break;
            }
        }
        return ParentWithID;
    }
}

在本例中,topOne最终将成为treeNode6 name=“Middle”。

如果要构建类结构,则需要使用递归方法的类。如果它变得太大,不确定它的效率会有多高。从树的顶部执行该方法

public class TreeNode  
{
    public string id { get; set; }
    public string name { get; set; }
    public string parentID { get; set; }
    public List<TreeNode> children { get; set; }

    public TreeNode() {
        children = new List<TreeNode>();
    }

    public TreeNode FindParentWithID(string ID)
    {
        TreeNode ParentWithID = null;

        //check my parentID if i am the one being looked for then return
        if (id == ID) return this;

        //search children
        foreach (TreeNode treeNode in children)
        {
            ParentWithID = treeNode.FindParentWithID(ID);

            if (ParentWithID != null)
            {
                break;
            }
        }
        return ParentWithID;
    }
}

在本例中,topOne最终将成为treeNode6 name=“Middle”。

您的
树列表是否总是只包含父级(因此始终是长度为1的列表)?还是我错了?我的意思是,这就是代码现在所做的,但这就是我在这篇文章中试图解决的问题。我不能完全确定我是否理解您的问题。问题是,鉴于您的
DataTable
有四项,您是希望
BuildTree()
返回一个包含四个
TreeNode
元素且父子关系设置正确的列表,还是希望它只返回根
TreeNode
对象,它的每个子元素都将包含定义树的其他元素?哦,我明白了-这两个元素中的后一个是我的目标。因此,使用示例
DataTable
,我的根
TreeNode
的ID为ABCD-12345。它将有一个ID为ABCD-23456的单个子
TreeNode
对象的列表。该
TreeNode
将依次具有一个包含两个子
TreeNode
对象的列表,ID分别为ABCD-34567和ABCD-45678。问题是我不知道这些树的嵌套深度会有多深。你的
树列表
是否总是只包含父树(因此总是有一个长度为1的列表)?还是我错了?我的意思是,这就是代码现在所做的,但这就是我在这篇文章中试图解决的问题。我不能完全确定我是否理解您的问题。问题是,鉴于您的
DataTable
有四项,您是希望
BuildTree()
返回一个包含四个
TreeNode
元素且父子关系设置正确的列表,还是希望它只返回根
TreeNode
对象,它的每个子元素都将包含定义树的其他元素?哦,我明白了-这两个元素中的后一个是我的目标。因此,使用示例
DataTable
,我的根
TreeNode
的ID为ABCD-12345。它将有一个ID为ABCD-23456的单个子
TreeNode
对象的列表。那棵树