2013-03-14 37 views
7

我目前正在编写一个程序来帮助写Lore。每个书对象都可以是父母并且有孩子。这意味着每个孩子都可以有孩子等无限。我正在处理一个ToString()方法,它可以使用递归来解释这个问题,但我一直在收到一个StackOverflowException。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(); 
    } 
} 
+6

通过在'stackoverflow.com查询 – 2013-03-14 09:15:37

+1

@SiGanteng我正在考虑做笑话,但我不选择; P – OmniOwl 2013-03-14 09:16:29

+0

在'isParent'分支内调用'GetAllChildren(book,sb)'后面的想法是什么? ?请注意,'book'和'sb'都没有被改变。 – 2013-03-14 09:19:03

回答

8

我想你的意思是:

if (book.isParent) 
{ 
    foreach (var child in book.Children) 
     GetAllChildren(child, sb); 
} 

否则你只是调用GetAllChildren方法具有相同的参数(book, sb)一遍又一遍。


附注 - 你仍然有一些问题,因为在GetAllChildren停止条件是通过迭代的孩子,当它不应该(如果不是家长,它不应该有孩子)。它应该返回它自己的名字。此外,每个孩子还应该在上面的foreach循环中追加它的名字(或者实际上,每本书都应该附加自己的名字)。 (注意这些变化)的方法应该是静态的,因为它与任何给定的实例都不相关(这引出了下面的建议)。


建议 - 我建议像下面代替(未经测试,需要在格式化一些工作):

//name changed to reflect what it really does 
//also changed to be an instance method (we no longer pass in a Book) 
//added listThisBooksName parameter to allow supressing the topmost book's output 
private void AppendAllChildren(StringBuilder sb, int level = 0, 
    bool listThisBooksName = false) 
{ 
    if (listThisBooksName) 
    { 
     //append ourself here 

     //first indent however far we need to 
     sb.Append(new String('\t', level)); 

     //now add our name 
     sb.Append(this.Name); 

     //and a newline (you can strip the last one later if you want) 
     sb.Append('\n'); 
    } 

    //forget the "isParent" property, just check if it has any children 
    //we don't need Children.Any() because the foreach will just iterate 0 times 
    //you might also consider using a List<Book> instead of an array for Children 
    if (this.Children != null) 
     foreach (var child in this.Children) 
      child.AppendAllChildren(sb, level+1, true); 
} 
+0

我从第一个注释中尝试了您的代码,而不是您的静态代码,并停止了获取异常,但请查看我的编辑。该方法仍然关闭。 – OmniOwl 2013-03-14 09:27:19

+0

@Vipar你看过我的最新编辑吗? (刚才) – 2013-03-14 09:35:28

+0

几乎完美。父列表本身虽然是小孩。 – OmniOwl 2013-03-14 09:37:40

2

这不是问题:

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

你再次调用相同的方法?我认为上面应该遍历孩子,并为每个孩子Book致电GetAllChildren。只有输出名称如果您的Book有任何孩子。

2

您的递归在同一本书上递归,而该书的IsParent为true。如果这本书是父母,你可能想要通过所有的孩子递归。