Метод расширения StringBuilder для добавления коллекции в C#
-
20-08-2019 - |
Вопрос
В 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.Я не совсем уверен, как написать код, чтобы лямбда-выражения работали с дженериками.
Решение
Использовать 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));
}
Другие советы
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 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.
Что-то вроде:
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());
}
Моя версия:
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());
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;
}
String peopleAndorders = SB.AppendCollection (People, p => p.toString ()). AppleCoLection (Orders, O => O.ToString ()). ToString ();
И я согласен с Дженнифер по поводу случая по умолчанию:
public static StringBuilder AppendCollection<TItem>(
this StringBuilder builder,
IEnumerable<TItem> items)
{
return AppendCollection(builder, items, x=>x.ToString());
}
String peopleAndorders = SB.AppendCollection (People) .AppendCollection (orders) .toString ();
Что должен вернуть этот метод?Я вижу строку, но почему, если вы добавляете ее к 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)));
}
(это то же самое, что сказал Бруно Конде)
А теперь он вам уже и не нужен :)