递归函数中的 StackOverFlowException

StackOverFlowException inside a recursive function

我在数据库中有一个 table 如下:

MenuItem
-------------
MenuItemId    1 --------+
MenuItemName            |
ParentId      * --------+

现在我已经编写了一个递归函数来获取所有父菜单项及其子项。

private ICollection<MenuItem> GetAllChildrenOfSpecificMenuItemRecursively(MenuItem menuItem, IEnumerable<MenuItem> menuItems)
{
    ICollection<MenuItem>  Children = null;
    foreach (MenuItem mi in menuItems)
    {
        if (mi.ParentMenuItemId != null)
        {
            if (mi.ParentMenuItemId == menuItem.MenuItemId)
            {
                Children.Add(mi);
            }
            else
            {
                return GetAllChildrenOfSpecificMenuItemRecursively(mi, menuItems);
            }
        }
    }

    return Children;
}

现在,我从另一个函数调用它,如下所示:

public IEnumerable<MenuItem> GetAllParentMenuItemsWithChildren()
{
    List<MenuItem> MenuItems = new List<MenuItem>();
    IEnumerable<MenuItem> AllMenuItems = null;

    using (MaxContext entityContext = new MaxContext())
    {
        AllMenuItems = (from e in entityContext.MenuItemSet select e).ToList();

        foreach (MenuItem menuItem in entityContext.MenuItemSet)
        {
            if (menuItem.ParentMenuItemId == null)
            {
                menuItem.Children = GetAllChildrenOfSpecificMenuItemRecursively(menuItem, AllMenuItems);
                MenuItems.Add(menuItem);
            }
        }
    }

    return MenuItems;
}

但是它在递归函数中给了我 WhosebugException。我确定我在该功能中犯了一个小错误。谁能指出那个错误?

您的 GetAllChildrenOfSpecificMenuItemRecursively() 总是与 mi 递归。它应该使用 mi.ParentMenuItemId 递归。

为什么你总是将相同的 menuItems colleciton 传递给递归函数?

您的代码应该类似于:

private IEnumerable<MenuItem> GetAllChildrenOfSpecificMenuItemRecursively(MenuItem menuItem)
{
    var children = new List<MenuItem>();
    foreach (MenuItem mi in menuItem.Children)
    { 
        // Why are you checking this?
        if (mi.ParentMenuItemId != null)
        {
            // Why are you checking this?
            if (mi.ParentMenuItemId == menuItem.MenuItemId)
            {
                children.Add(mi);
            }
            else
            {

                children.AddRange(GetAllChildrenOfSpecificMenuItemRecursively(mi))
            }
        }
    }

    return Children;
}

从方法名称来看,这就是它应该做的所有事情:

private IEnumerable<MenuItem> GetAllChildrenOfSpecificMenuItemRecursively(MenuItem menuItem)
{
    var children = new List<MenuItem>();
    if (menuItem.Children == null) return children;

    foreach (MenuItem mi in menuItem.Children)
    { 
       children.Add(mi);
       children.AddRange(GetAllChildrenOfSpecificMenuItemRecursively(mi));       
    }

    return Children;
}

编辑:

public class MenuItem
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Name { get; set; }
    public int ParentId { get; set; }

    public virtual MenuItem Parent { get; set; }

    [InverseProperty("Parent")]
    public virtual ICollection<MenuItem> Children { get; set; }
}

我认为有一种不使用递归的更简单(也许更快)的方法可以做到这一点。像这样:

    public ICollection<MenuItem> GetMenuItemsAsTreeList()
    {
        AllMenuItems = entityContext.MenuItemSet.ToList();

        Dictionary<int, MenuItem> dic = AllMenuItems.ToDictionary(n => n.Id, n => n);

        List<MenuItem> rootMenuItems = new List<MenuItem>();

        foreach (MenuItem menuItem in AllMenuItems)
        {
            if (menuItem.ParentMenuItemId.HasValue)
            {
                MenuItem parent = dic[menuItem.ParentMenuItemId.Value];
                menuItem.ParentMenuItem = parent;
                parent.SubMenuItems.Add(menuItem);
            }
            else
            {
                rootMenuItems.Add(menuItem);
            }
        }

        return rootMenuItems;
    }