递归函数内的StackOverFlowException

时间:2015-02-12 23:58:59

标签: c# recursion

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

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

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

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;
}

但是它在递归函数中给了我stackoverflowException。我确信我在这个功能上犯了一个小错误。任何人都可以指出这个错误吗?

3 个答案:

答案 0 :(得分:3)

您的GetAllChildrenOfSpecificMenuItemRecursively()始终使用mi进行递归。它应该用mi.ParentMenuItemId代替。

答案 1 :(得分:1)

为什么总是将相同的menuItems收藏品传递给递归函数?

你的代码应该是:

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; }
}

答案 2 :(得分:1)

我认为在不使用递归的情况下,有一种更简单(也许更快)的方法。像这样:

    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;
    }