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