2013-03-14 10 views
7

Ich schreibe gerade ein Programm, um zu helfen, Lore zu schreiben. Jedes Buchobjekt kann ein Elternteil sein und Kinder haben. Das bedeutet, dass jedes Kind Kinder usw. ins Unendliche haben kann. Ich arbeitete an einer ToString() -Methode, die dies mithilfe der Rekursion berücksichtigen könnte, aber ich erhalte immer eine StackOverflowException.StackOverflowException verursacht durch Rekursion

Ich weiß, was es bedeutet, aber ich habe Zweifel, wie ich es beheben kann. Ich bin ziemlich neu in C#, habe aber ziemlich viel Java-Erfahrung. Wenn Sie also einen Trick oder etwas wissen, was ich verpasst habe, lassen Sie es mich wissen!

Also meine Frage ist: Wie vermeide ich eine StackOverflow-Ausnahme? Das Problem ist in GetAllChildren()

EDIT:

Nach einem Test läuft, sollte ich so etwas wie dieses:

Name: a 
Children: 
b 
c 
    d 
e 

Mit dem Code von @lc. Ich erhalte die folgende Ausgabe:

Name: a 
Children: No Children b 
c 
e 
    b 
c 
e 
    b 
c 
e 

Hier ist die Klasse:

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

von stackoverflow.com' –

+1

@SiGanteng bei 'fragen Ich machte den Witz bedenkt, aber ich wählte nicht zu; P – OmniOwl

+0

Was das Denken hinter Aufruf' GetAllChildren (Buch, sb) war; 'innerhalb der' isParent' Zweig ?Beachten Sie, dass weder 'book' noch' sb' verändert wurden. –

Antwort

8

Ich glaube, Sie gemeint:

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

Ansonsten sind Sie nur die GetAllChildren Methode mit den gleichen Parametern aufrufen (book, sb) immer und immer wieder.


Randnotiz - Sie noch einige Probleme haben, weil die Stoppbedingung im GetAllChildren durch Kinder laufen, wenn es nicht (wenn es nicht ein Elternteil ist, sollte es keine Kinder haben). Es sollte stattdessen seinen eigenen Namen zurückgeben. Darüber hinaus sollte jedes Kind seinen Namen auch in der obigen foreach-Schleife anhängen (oder eigentlich sollte jedes Buch seinen eigenen Namen anhängen).

Seitennotiz 2 - die Methode wie geschrieben (mit diesen Änderungen) sollte wirklich statisch sein, da sie nicht auf eine bestimmte Instanz bezogen ist (was mich zum folgenden Vorschlag bringt).


Vorschlag - ich würde so etwas wie die folgenden stattdessen empfehlen (ungetestet und wird noch einige Arbeiten an der Formatierung müssen):

//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

Ich habe Ihren Code von der ersten Note aus getestet, nicht von Ihrer statischen, und habe die Ausnahme nicht mehr erhalten, aber sehen Sie sich meine Editierung an. Die Methode ist noch aus. – OmniOwl

+0

@Vipar Haben Sie sich meine neueste Bearbeitung angeschaut? (Gerade jetzt) ​​ –

+0

Fast perfekt. Die Elternliste selbst jedoch als Kind. – OmniOwl

2

Ist das nicht das Problem:

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

und Sie rufen die gleiche Methode noch einmal an? Ich denke, dass das oben genannte durch die Kinder iterieren und GetAllChildren für jedes Kind Book anrufen sollte. Geben Sie nur den Namen aus, wenn Ihr Bookkeine Kinder hat.

2

Sie Rekursion rekursiv auf dem gleichen Buch, während das IsParent dieses Buches wahr ist. Sie möchten wahrscheinlich alle Kinder rekrutieren, wenn das Buch ein Elternteil ist.

Verwandte Themen