Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 由递归引起的StackOverflowException_C#_Recursion_Stack Overflow - Fatal编程技术网

C# 由递归引起的StackOverflowException

C# 由递归引起的StackOverflowException,c#,recursion,stack-overflow,C#,Recursion,Stack Overflow,我目前正在编写一个程序来帮助编写知识。每个Book对象都可以是父对象并具有子对象。这意味着每个孩子都可以拥有无限的孩子。我正在研究一个ToString()方法,该方法可以使用递归来解释这个问题,但我一直得到一个StackOverflowException 我知道这意味着什么,但我不知道如何修复它。我对C#相当陌生,但有相当多的Java经验,所以如果你知道我错过的技巧或东西,请告诉我 所以我的问题是:如何避免StackOverflow异常?问题出在GetAllChildren()中 编辑: 运行测

我目前正在编写一个程序来帮助编写知识。每个Book对象都可以是父对象并具有子对象。这意味着每个孩子都可以拥有无限的孩子。我正在研究一个ToString()方法,该方法可以使用递归来解释这个问题,但我一直得到一个StackOverflowException

我知道这意味着什么,但我不知道如何修复它。我对C#相当陌生,但有相当多的Java经验,所以如果你知道我错过的技巧或东西,请告诉我

所以我的问题是:如何避免StackOverflow异常?问题出在GetAllChildren()中

编辑:

运行测试后,我应该得到如下结果:

Name: a
Children:
b
c
    d
e
使用@lc中的代码。我得到以下输出:

Name: a
Children: No Children   b
c
e
    b
c
e
    b
c
e
下面是课堂:

class Book
{
    private String name;
    private Book[] children;
    private StringBuilder text;
    private Boolean isParent;

    public Book(String name, Book[] children, StringBuilder text, Boolean isParent)
    {
        this.name = name;
        this.children = children;
        this.text = text;
        this.isParent = isParent;
    }

    /**
     * Most likely all possible Constructors
     * */
    public Book(String name, Book[] children) : this(name, children, new StringBuilder("No Text"), true) { }
    public Book(String name, String text) : this(name, new Book[0], new StringBuilder(text), false) { }
    public Book(String name, StringBuilder text) : this(name, new Book[0], text, false) { }
    public Book(String name) : this(name, new Book[0], new StringBuilder("No Text"), false) { }
    public Book(Book[] children, String text) : this("Unnamed Book", children, new StringBuilder(text), true) { }
    public Book(Book[] children, StringBuilder text) : this("Unnamed Book", children, text, true) { }
    public Book(Book[] children) : this("Unnamed Book", children, new StringBuilder("No Text"), true) { }
    public Book(StringBuilder text) : this("Unnamed Book", new Book[0], text, false) { }
    public Book() : this("Unnamed Book", new Book[0], new StringBuilder("No Text"), false) { }

    public String Name
    {
        get { return name; }
        set { name = value; }
    }

    public Book[] Children
    {
        get { return children; }
        set { children = value; }
    }

    /**
     * Will Return the StringBuilder Object of this Text
     * */

    public StringBuilder Text
    {
        get { return text; }
        set { text = value; }
    }

    public Boolean IsParent
    {
        get { return isParent; }
        set { isParent = value; }
    }

    private void GetAllChildren(Book book, StringBuilder sb)
    {
        if (book.isParent)
        {
            GetAllChildren(book, sb);
        }
        else
        {
            sb.Append("\t");
            foreach (Book b in children)
            {
                sb.Append(b.Name + "\n");
            }
        }
    }

    public override String ToString()
    {
        StringBuilder sChildren = new StringBuilder("No Children");
        if (children.Length != 0)
        {
            GetAllChildren(this, sChildren);
        }

        return "Name: " + name + "\n" +
            "Children: " + sChildren.ToString();
    }
}
我想你的意思是:

if (book.isParent)
{
    foreach (var child in book.Children)
        GetAllChildren(child, sb);
}
否则,您只需使用相同的参数(
book,sb
)反复调用
GetAllChildren
方法


旁注-您仍然存在一些问题,因为
GetAllChildren
中的停止条件正在迭代子项,而它本不应该迭代(如果它不是父项,则不应该有子项)。它应该返回自己的名称。此外,每个孩子还应该在上面的foreach循环中附加自己的名字(或者实际上,每本书都应该附加自己的名字)

旁注2——编写的方法(有这些更改)应该是静态的,因为它与任何给定实例都不相关(这让我想到了下面的建议)


建议-我会推荐如下内容(未经测试,需要在格式方面做一些工作):

//名称已更改以反映其实际功能
//也更改为实例方法(我们不再在书中传递)
//添加了listThisBooksName参数,以允许抑制最顶层书籍的输出
私有void AppendAllChildren(StringBuilder sb,int level=0,
bool listThisBooksName=false)
{
如果(ListThisBookName)
{
//把自己放在这里
//第一个缩进,不管我们需要缩进多远
sb.Append(新字符串('\t',level));
//现在加上我们的名字
某人加上(这个名字);
//和换行符(如果需要,您可以稍后删除最后一行)
sb.追加('\n');
}
//忘记“isParent”属性,只需检查它是否有子级
//我们不需要Children.Any(),因为foreach只会迭代0次
//您也可以考虑使用列表代替儿童的数组。
if(this.Children!=null)
foreach(此.Children中的var child)
子项。附加所有子项(sb,级别+1,正确);
}
这不是问题所在:

    if (book.isParent)
    {
        GetAllChildren(book, sb);
    }

你又调用了同样的方法?我认为上面的内容应该遍历这些子项,并为每个子项调用
GetAllChildren
。仅当您的
没有任何子项时才输出名称。

您的递归在同一本书上递归,而该书的IsParent为true。如果这本书是一位家长的话,你可能想在所有的孩子身上反复出现。

通过询问
stackoverflow.com
@sigateng,我正在考虑开玩笑,但我选择了不开玩笑;p调用
GetAllChildren(book,sb)背后的想法是什么
isParent
分支内?请注意,
book
sb
均未被更改。@Damien\u不信者不确定我是否理解您的问题。我从第一个注释开始尝试了您的代码,而不是静态注释,并停止获取异常,但请查看我的编辑。这个方法仍然不可行,几乎完美。但父项列表本身是子项。@Vipar不知道您想将最顶层的父项与子项分开列出。检查我的编辑。我想你明白这段代码在做什么?好了!完美的非常感谢男士:)对于未来的读者来说,静态方法是有效的!
    if (book.isParent)
    {
        GetAllChildren(book, sb);
    }