Метод расширения StringBuilder для добавления коллекции в C#

В C# я пытаюсь создать метод расширения для StringBuilder под названием AppendCollection (), который позволил бы мне сделать это:

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 получал бы строчку для каждого человека в списке. Каждая строка будет результатом p.ToString (). То же самое и для stringOrders. Я не совсем уверен, как написать код, чтобы лямбды работали с дженериками.

По какой причине вы не хотите использовать для этого String.Join ()?

philsquared 09.12.2008 22:53

Я хотел бы иметь возможность передавать лямбду в качестве средства форматирования, чтобы вы могли делать такие вещи, как sb1.AppendCollection (people, => p.FirstName + "" + p.LastName);

Lance Fisher 09.12.2008 23:16
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
2
6 957
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Что этот метод должен вернуть? Я вижу строку, но почему, если вы добавляете StringBuilder?

То, что вы пытаетесь сделать, довольно просто, но вам нужно точно объяснить, чего вы хотите.

Обновлять:

Вот мое мнение. Использование метода расширения для этого глупо и бессмысленно, если вы просто собираетесь передать новый StringBuilder и вернуть строку.

Обновление 2:

Теперь, когда я вижу такое использование, то, что вы делаете, - плохая практика. В идеале вы должны делать что-то вроде:

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

Обновление 3:

После дополнительных разъяснений:

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

(что то же самое, что сказал Бруно Конде)

И теперь он вам больше не нужен :)

Итак, меня проголосовали против, потому что я прошу разъяснений? Это дух ...

leppie 09.12.2008 22:11

Я думаю, дело в том, что ваш пост - это не ответ, это вопрос. Я не голосовал против.

Jason Jackson 09.12.2008 22:14

Вы можете избежать голосов против, попросив разъяснений в комментарии, а не в ответе. Я также не голосовал против. Это то, что я делаю, чтобы избегать людей, которые думают, что все, что не является ответом, бесполезно.

tvanfosson 09.12.2008 22:17

Но я этого не хотел. Я собирался опубликовать ответ, как только у меня будет разъяснение ...

leppie 09.12.2008 22:18

Метод должен возвращать void, а не строку, как у меня вначале. Он должен работать как AppendLine (), но позволять передавать функцию сбора и форматирования.

Lance Fisher 09.12.2008 22:42

Я хотел бы иметь метод расширения для StringBuilder, потому что есть другие строки, которые я хочу добавить в построитель до и после моей коллекции. Как вы думаете, почему это плохая практика?

Lance Fisher 09.12.2008 23:19

Ну, вы не объяснили использование, поэтому у меня было так много начальных вопросов.

leppie 10.12.2008 00:17

Для ясности, я изначально не голосовал против вас, хотя я могу полностью понять, почему некоторые люди могли проголосовать.

Jason Jackson 10.12.2008 23:26
Ответ принят как подходящий

Используйте делегат 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));
}

Мне это не нравится, поскольку это нарушает парадигму StringBuilder. Методы StringBuilder должны просто продолжать добавлять во внутренний буфер, пока ToString не будет вызван в построителе. Он сочетает в себе шаги добавления / добавления в строку и не похож на другие методы добавления в StringBuilder.

tvanfosson 09.12.2008 22:21

Конечно, я обновил ответ, чтобы упомянуть свое мнение по этому поводу, но это конкретно задано в вопросе.

mmx 09.12.2008 22:23

Я полностью согласен. Я набрал этот пример кода слишком быстро. Я обновил вопрос.

Lance Fisher 09.12.2008 22:37

Я не уверен, что вам нужно так много работать:

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

Используется как

 List<Person> people = ...

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

Конечно, Person необходимо переопределить ToString (), чтобы получить правильный вывод для объекта Person.

Используя лямбда, вы можете форматировать элемент в коллекции, как хотите.

Lance Fisher 09.12.2008 22:38

Конечно, но вы просто вызываете ToString ()

tvanfosson 10.12.2008 02:53

Наверное, мне следовало написать что-то вроде sb1.AppendCollection (p.FirstName + "" + p.LastName) в этом примере. Вот какая гибкость мне нравится в этой функции.

Lance Fisher 11.12.2008 10:19

Лэнс, в этом случае я бы предпочел предоставить перегрузку для AppendCollection, которая позволяет вам указать форматирование, а затем написать собственный модуль форматирования для вашего типа. Таким образом, вы используете установленные интерфейсы и упрощаете повторное использование кода, вместо того, чтобы создавать совершенно новый API, нарушающий интерфейс.

Konrad Rudolph 18.02.2009 19:40

Что-то типа:

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

Я бы добавил полезное значение по умолчанию, чтобы сохранить указание лямбда в 90% случаев ...

   public static void AppendCollection<TItem>(this StringBuilder builder, IEnumerable<TItem> items)
  {
      AppendCollection(builder, items, x=>x.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();

  }
}

Однако я думаю, вам будет лучше, если он вернет StringBuilder. Таким образом вы могли связать это:

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

  }

строка peopleAndOrders = sb.AppendCollection (люди, p => p.ToString ()) .AppendCollection (заказы, o => o.ToString ()). ToString ();

И я согласен с Дженнифер насчет случая по умолчанию:

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

строка peopleAndOrders = sb.AppendCollection (люди) .AppendCollection (заказы) .ToString ();

Цепочка хороша, но я обычно предпочитаю, чтобы мои методы расширения работали так же, как и другие методы класса. Из-за изменения базовой схемы работы становится труднее понять.

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

Я бы не стал возвращать строку, я просто добавил бы ее в исходный Stringbuilder, который был передан.

Моя версия:

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

но в этом случае вы не должны возвращать строку. Я бы предпочел следующее:

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

для использования как:

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

Я согласен с тем, что мне не следует возвращать строку. Я обновил вопрос.

Lance Fisher 09.12.2008 22:40

Другие вопросы по теме