Domanda

In C #, sto cercando di creare un metodo di estensione per StringBuilder chiamato AppendCollection () che mi permetta di fare questo:

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 finirebbe con una riga per ogni persona nell'elenco. Ogni riga sarebbe il risultato di p.ToString (). Allo stesso modo per stringOrders. Non sono sicuro di come scrivere il codice per far funzionare i lambda con i generici.

È stato utile?

Soluzione

Utilizza il Func<T,string> delegato.

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

Altri suggerimenti

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

Non restituirei una stringa, la aggiungerei semplicemente allo Stringbuilder originale che è stato passato.

Non sono sicuro che tu debba lavorare così duramente:

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

Usato come

 List<Person> people = ...

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

Naturalmente, Person deve sovrascrivere ToString () per produrre l'output corretto per un oggetto Person.

Qualcosa del tipo:

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

Aggiungerei un utile default per salvare specificando la lambda nel 90% dei casi ...

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

La mia versione:

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

ma in questo caso non dovresti restituire una stringa. Preferirei quanto segue:

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

da usare come:

        sb.AppendCollection(people, p => p.ToString());
        sb.AppendCollection(orders, o => o.ToString());
        Console.WriteLine(sb.ToString());
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();

  }
}

Tuttavia, penso che farai meglio a restituire StringBuilder. In questo modo potresti incatenarlo:

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

  }

stringa peopleAndOrders =            sb.AppendCollection (people, p = > p.ToString ())              .AppendCollection (ordini, o = & Gt; o.ToString ()). ToString ();

E concordo con Jennifer sul caso predefinito:

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

stringa peopleAndOrders =            sb.AppendCollection (persone) .AppendCollection (ordini) .toString ();

Che cosa suppone questo metodo di restituire? Posso vedere una stringa, ma perché, se stai aggiungendo un StringBuilder?

Quello che stai cercando di fare è piuttosto semplice, ma devi spiegare esattamente cosa vuoi.

Aggiornamento:

Ecco la mia opinione. L'uso di un metodo di estensione per questo è stupido e inutile se hai intenzione di passare un nuovo StringBuilder e restituire una stringa.

Aggiornamento 2:

Ora che vedo quell'uso, quello che stai facendo è una cattiva pratica. Ciò che dovresti idealmente fare è qualcosa del tipo:

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

Aggiornamento 3:

Dopo ulteriori chiarimenti:

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

(che è lo stesso di bruno conde)

E ora non ne hai più bisogno :)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top