2008-12-09 9 views
5

En C#, je suis en train de construire une méthode d'extension pour StringBuilder appelé AppendCollection() qui me permettent de le faire:StringBuilder méthode d'extension pour l'ajout d'une collection 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 se retrouverait avec un ligne pour chaque personne de la liste. Chaque ligne serait le résultat de p.ToString(). De même pour stringOrders. Je ne sais pas trop comment écrire le code pour que les lambdas fonctionnent avec des génériques.

+0

une raison quelconque vous ne voulez pas utiliser String.Join() pour cela? – philsquared

+1

Je voudrais pouvoir passer un lambda en tant que formateur afin de pouvoir faire des choses comme sb1.AppendCollection (people, => p.FirstName + "" + p.LastName); –

Répondre

9

Utilisez le délégué 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

Je n'aime pas ça, car cela brise le paradigme de StringBuilder. Les méthodes sur StringBuilder devraient simplement continuer à s'ajouter au tampon interne jusqu'à ce que ToString soit appelé sur le générateur. Cela combine les étapes append/tostring et ne ressemble pas aux autres méthodes d'ajout sur StringBuilder. – tvanfosson

+0

Bien sûr, j'ai mis à jour la réponse pour mentionner mon opinion à ce sujet, mais elle est spécifiquement posée dans la question. –

+0

Je suis complètement d'accord. J'ai tapé cet exemple de code un peu trop vite. J'ai mis à jour la question. –

2

Quelle est cette méthode supposée renvoyer? Je peux voir une chaîne, mais pourquoi, si vous ajoutez un StringBuilder? Ce que vous essayez de faire est plutôt facile, mais vous devez expliquer exactement ce que vous voulez.

Mise à jour:

Voici mon. Utiliser une méthode d'extension pour cela est stupide et inutile si vous allez juste passer un nouveau StringBuilder et retourner une chaîne.

Mise à jour 2:

Maintenant que je vois que l'utilisation, ce que vous faites est une mauvaise pratique. Ce que vous devriez idéalement être en train de faire quelque chose comme:

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); 

Mise à jour 3:

Après plus de précisions:

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

(qui est le même que celui bruno conde dit)

Et maintenant vous n'en avez plus vraiment besoin :)

+0

Je suis donc rejeté, parce que je demande des éclaircissements? C'est l'esprit ... – leppie

+0

Je pense que le point est que votre message n'est pas une réponse, c'est une question. Je ne vous ai pas voté. –

+0

Alors je me parlais? – leppie

3

Je ne suis pas sûr que vous devez travailler dur que:

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

Utilisé comme

List<Person> people = ... 

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

Bien sûr, personne a besoin de passer outre ToString() pour produire la sortie correcte pour un objet Person.

+0

En utilisant le lambda, vous formater l'article dans la collection comme vous le souhaitez. –

+0

Bien sûr, mais vous appelez simplement ToString() – tvanfosson

+0

Je devrais probablement avoir écrit quelque chose comme sb1.AppendCollection (p.FirstName + "" + p.LastName) dans l'exemple. C'est la flexibilité que j'aime dans cette fonction. –

3

Quelque chose comme:

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

J'ajouterais en défaut utile pour sauver specifiying le lambda dans 90% des cas ...

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(); 

    } 
} 

Cependant, je pense que vous » Il vaudrait mieux que vous retourniez le StringBuilder. De cette façon, vous pourriez enchaîner:

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

    } 

chaîne peopleAndOrders = sb.AppendCollection (personnes, p => p.ToString()) .AppendCollection (orders, o => o.ToString()). ToString();

Je suis d'accord avec Jennifer sur le cas par défaut:

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

chaîne peopleAndOrders = sb.AppendCollection (personnes) .AppendCollection (commandes) .toString();

+0

Le chaînage est sympa, mais je préfère généralement mes méthodes d'extension pour travailler essentiellement de la même manière que les autres méthodes de la classe. Changer le modèle de base de la façon dont cela fonctionne rend plus difficile à comprendre. – 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)); 
      } 
     } 

Je ne retournerais pas une chaîne, je voudrais juste ajouter à la stringbuilder originale qui a été adoptée dans

+0

Oui, je suis d'accord.C'était une erreur. J'ai mis à jour la question. –

3

Ma version:.

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(); 
    } 

mais vous ne devriez pas retourner un chaîne dans ce cas. Je préférerais les suivantes:

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))); 
    } 

à utiliser comme:

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

Je suis d'accord que je ne devrais pas retourner une chaîne. J'ai mis à jour la question. –

Questions connexes