2008-12-09 17 views
5

En C#, yo estoy tratando de construir un método de extensión de StringBuilder llama AppendCollection() que dejarme hacer esto:StringBuilder para anexar una colección en C#

var sb1 = new StringBuilder(); 
var sb2 = new StringBuilder(); 
var people = new List<Person>() { ...init people here... }; 
var orders = new List<Orders>() { ...init orders here... }; 

sb1.AppendCollection(people, p => p.ToString()); 
sb2.AppendCollection(orders, o => o.ToString()); 

string stringPeople = sb1.ToString(); 
string stringOrders = sb2.ToString(); 

stringPeople terminaría con una línea para cada persona en la lista. Cada línea sería el resultado de p.ToString(). Del mismo modo para stringOrders. No estoy seguro de cómo escribir el código para que las lambdas funcionen con genéricos.

+0

algún motivo usted no desea utilizar string.join() para esto? – philsquared

+1

Me gustaría poder pasar un lambda como formateador para que pueda hacer cosas como sb1.AppendCollection (personas, => p.FirstName + "" + p.LastName); –

Respuesta

9

Utilice el delegado Func<T,string>.

public static void AppendCollection<T>(this StringBuilder sb, 
             IEnumerable<T> collection, Func<T, string> method) { 
    foreach(T x in collection) 
     sb.AppendLine(method(x)); 
} 
+0

No me gusta esto ya que rompe el paradigma de StringBuilder. Los métodos en StringBuilder deberían continuar agregándose al búfer interno hasta que se llame a ToString en el generador. Esto combina los pasos de append/tostring y no es como los otros métodos de agregar en StringBuilder. – tvanfosson

+0

Claro, actualicé la respuesta para mencionar mi opinión sobre esto, pero se pregunta específicamente en la pregunta. –

+0

Estoy totalmente de acuerdo. Escribí ese código de ejemplo un poco demasiado rápido. He actualizado la pregunta. –

2

¿Qué se supone que debe devolver este método? Puedo ver una cadena, pero ¿por qué, si agregas un StringBuilder?

Lo que intenta hacer es bastante fácil, pero necesita explicar exactamente lo que desea.

Actualización:

Esta es mi opinión. Usar un método de extensión para esto es estúpido e inútil si solo vas a pasar un nuevo StringBuilder y devolver una cadena.

Actualización 2:

Ahora que veo que el uso, lo que está haciendo es una mala práctica. Lo que idealmente debería estar haciendo es algo así como:

public static string Print<T>(this IEnumerable<T> col, Func<T,string> printer) 
{ 
    var sb = new StringBuilder(); 
    foreach (T t in col) 
    { 
    sb.AppendLine(printer(t)); 
    } 
    return sb.ToString(); 
} 

string[] col = { "Foo" , "Bar" }; 
string lines = col.Print(s => s); 

Actualización 3:

Después de más aclaraciones:

public static void AppendCollection<T>(this StringBuilder sb, 
    List<T> col, Func<T,string> printer) 
{ 
    col.ForEach(o => sb.AppendLine(printer(o))); 
} 

(que es el mismo que dicho Bruno Conde)

Y ahora ya no lo necesitas :)

+0

Entonces, ¿me están rechazando, porque pido una aclaración? Ese es el espíritu ... – leppie

+0

Creo que el punto es que su publicación no es una respuesta, es una pregunta. No te voté. –

+0

Entonces, ¿estaba hablando solo? – leppie

3

No estoy seguro de que necesita trabajar tan duro:

public static void AppendCollection(this StringBuilder builder, 
             ICollection collection) 
{ 
    foreach (var item in collection) 
    { 
     builder.AppendLine(Convert.ToString(item)); 
    } 
} 

Utilizado como

List<Person> people = ... 

StringBuilder builder = new StringBuilder(); 
builder.AppendCollection(people); 
var s = builder.ToString(); 

Por supuesto, la persona tiene que anular ToString() para producir la salida correcta para un objeto Persona.

+0

Al usar la lambda, puede formatear el elemento en la colección como quiera. –

+0

Claro, pero solo llama a ToString() – tvanfosson

+0

Probablemente debería haber escrito algo como sb1.AppendCollection (p.FirstName + "" + p.LastName) en el ejemplo. Esa es la flexibilidad que me gusta en esta función. –

3

Algo así como:

public static void AppendCollection<TItem>(this StringBuilder builder, IEnumerable<TItem> items, Func<TItem, string> valueSelector) 
    { 
     foreach(TItem item in items) 
     { 
      builder.Append(valueSelector(item)); 
     } 
    } 

Yo añadiría en una forma predeterminada útil para ahorrar especificando la lambda en el 90% de los casos ...

public static void AppendCollection<TItem>(this StringBuilder builder, IEnumerable<TItem> items) 
    { 
     AppendCollection(builder, items, x=>x.ToString()); 
    } 
2
static class SBExtention 
{ 
    static string AppendCollection<T>(this StringBuilder sb, 
            IEnumerable<T> coll, 
            Func<T,string> action) 
    { 
     foreach(T t in coll) 
     { 
      sb.Append(action(t)); 
      sb.Append("\n"); 
     } 
     return sb.ToString(); 

    } 
} 

Sin embargo, creo que' Será mejor que lo devuelva StringBuilder. De esa manera usted podría encadenarse que:

static StringBuilder AppendCollection<T>(this StringBuilder sb, 
            IEnumerable<T> coll, 
            Func<T,string> action) 
    { 
     // same 
     return sb; 

    } 

peopleAndOrders cadena = sb.AppendCollection (gente, p => p.ToString()) .AppendCollection (orders, o => o.ToString()). ToString();

Y estoy de acuerdo con Jennifer sobre el caso por defecto:

public static StringBuilder AppendCollection<TItem>(
        this StringBuilder builder, 
        IEnumerable<TItem> items) 
    { 
     return AppendCollection(builder, items, x=>x.ToString()); 
    } 

peopleAndOrders cadena = sb.AppendCollection (personas) .AppendCollection (órdenes) .toString();

+0

El proceso de encadenamiento es bueno, pero generalmente prefiero que mis métodos de extensión funcionen básicamente de la misma manera que los demás métodos de la clase. Cambiar el patrón básico de cómo funciona hace que sea más difícil de entender. – tvanfosson

4
public static void AppendCollection<T>(this StringBuilder builder, IEnumerable<T> list, Func<T,string> func) 
     { 
      foreach (var item in list) 
      { 
       builder.AppendLine(func(item)); 
      } 
     } 

no volvería una cadena, me acaba de añadirlo al StringBuilder original que fue aprobada en

+0

Sí, estoy de acuerdo.Eso fue un error. Actualicé la pregunta. –

3

Mi versión:.

public static string AppendCollection<T>(this StringBuilder sb, IEnumerable<T> enumerable, Func<T, string> method) 
    { 
     List<T> l = new List<T>(enumerable); 
     l.ForEach(item => sb.AppendLine(method(item))); 
     return sb.ToString(); 
    } 

pero no debería devolver una cadena en este caso. Yo preferiría el siguiente:

public static void AppendCollection<T>(this StringBuilder sb, IEnumerable<T> enumerable, Func<T, string> method) 
    { 
     List<T> l = new List<T>(enumerable); 
     l.ForEach(item => sb.AppendLine(method(item))); 
    } 

para ser utilizado como:

 sb.AppendCollection(people, p => p.ToString()); 
     sb.AppendCollection(orders, o => o.ToString()); 
     Console.WriteLine(sb.ToString()); 
+0

Acepto que no debo devolver una cadena. He actualizado la pregunta. –