2013-01-08 2 views
-1

У меня есть класс (например, Foo), который переопределяет метод ToString для печати его внутреннего состояния. Этот класс имеет коллекцию Foo - это дочерние элементы. Дети также могут иметь ребенок и т.д.C# ToString() - печать дочерних элементов

я ищу решение для реализации в ToString() таким образом, что он будет отступом дочерних элементов автоматически, например:

Parent Foo 
Child1 Foo 
    Child1.1 Foo 
Child2 Foo 
    Child2.1 Foo 
    Child2.2 Foo 
+0

Вы хотите сказать, что вызов 'ToString' в корневой папке должен печатать все дерево вызовов ToString? – Tudor

+0

Я не думаю, что каждый объект 'Foo' отслеживает глубину в дереве –

+0

Да и автоматически определяйте уровень отступа. – jjczopek

ответ

3

Решение состоит в том, чтобы использовать ToString() только как «точку входа», которая вызывается в корневой части поддерева для вывода. Этот метод ToString() может вызывать частный метод ToIndentedString(int), который принимает текущий уровень отступов в качестве аргумента. Этот метод будет возвращать строковое представление текущего узла в указанном отступа, а также струнные представления всех дочерних узлов при вдавливании + 1 и т.д.

public string ToString() 
{ 
    return ToIndentedString(0); 
} 

private string ToIndentedString(int indentation) 
{ 
    StringBuilder result = new StringBuilder(); 
    result.Append(' ', indentation); 
    result.Append(Environment.NewLine); 
    foreach (Foo child in children) { 
     result.Append(child.ToIndentedString(indentation + 1)); 
    } 
    return result.ToString(); 
} 
+1

Если вы ожидаете, что нетривиальный размер дерева также рассмотрит возможность рекурсивно передавать «StringBuilder», вместо того, чтобы иметь один на узел, так как он будет более эффективным. – Servy

+0

@Servy: Абсолютно верно, замечательный комментарий :-) –

+0

в foreach, вызов child.ToIndentedString не будет работать, поскольку метод является приватным. – Jastill

0
string spacing = " "; 
string newLineSpacing = string.Format("{0}{1}", Environment.NewLine, spacing); 
StringBuilder sb = new StringBuilder("mydata"); 
foreach (Foo child in children) 
{ 
    sb.Append(Environment.NewLine); 
    sb.Append(spacing); 
    sb.Append(child.ToString().Replace(Environment.NewLine, newLineSpacing)); 
} 

Непроверен, как я m в настоящее время перестраивает мою машину разработки.

0

Вы также можете использовать IFormattable на Foo, как это:

public class Foo : IFormattable 
{ 
    public string Text { get; set; } 
    public IList<Foo> InnerList { get; set; } 

    public string ToString(string format, IFormatProvider formatProvider) 
    { 
     if (String.IsNullOrEmpty(format)) format = "0"; 
     if (formatProvider == null) formatProvider = CultureInfo.CurrentCulture; 

     int indent = 0; 
     Int32.TryParse(format, out indent); 
     string indentString = ""; 
     while(indent > indentString.Length) 
     { 
      indentString += " "; 
     } 
     var toString = String.Format("{0}{1}", indentString, Text); 
     foreach (Foo foo in InnerList ?? new List<Foo>()) 
     { 
      toString += String.Format("\n{0}", foo.ToString((indent + 1).ToString(), formatProvider)); 
     } 
     return toString; 
    } 

    public override string ToString() 
    { 
     return ToString("0", CultureInfo.CurrentCulture); 
    } 
} 

В этом случае вы также можете сделать:

String.Format("{0:5}", foo); // Start with 5 indents 

Или

foo.ToString("7", CultureInfo.CurrentCulture); // Also start with indents (7 in this case) 
Смежные вопросы