Разделенная строка, созданная в цикле

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

StringBuilder sb = new StringBuilder();
while(reader.Read())
{
  sb.Append(reader[0]);
  sb.Append("<br />");
}
string result = sb.ToString();
result = result.Remove(result.LastIndexOf("<br />")); // <-

или создание строки SQL-запроса;

StringBuilder sb = new StringBuilder();
foreach(string v in values)
{
  sb.Append(v);
  sb.Append(",");
}
string query = sb.ToString()
query = query.Remove(query.LastIndexOf(",")); // <-
query = String.Concat("INSERT INTO [foo] ([bar]) VALUES(", query, ")");

Это лучшее, что я нашел:

List<string> list = new List<string>;
while(reader.Read())
{
  list.Add(reader[0]);
}
string result = String.Join("<br />", list.ToArray());

Изменить: Я знаю о StringBuilder, я не использовал его здесь только для некоторой ясности. Моя общая идея не использует Remove/LastIndexOf!

Ответ 1

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

private IEnumerable<string> ReadAllStrings(DataReader reader)
{
    while(reader.Read())
        yield return reader[0];
}


String.Join("<br />", ReadAllStrings(reader).ToArray());

Если бы я делал это много, я мог бы рассмотреть метод расширения:

public static class Extensions
{
    public static string JoinWith(this IEnumerable<string> strings, string separator)
    {
        return String.Join(separator, strings.ToArray());
    }
}

Тогда мой код будет выглядеть так:

ReadAllStrings(reader).JoinWith("<br />");

Ответ 2

Как насчет:

StringBuilder builder;
while (reader.Read())
{
    if( builder == null )
    {
        builder = new StringBuilder(reader[0]);
    }
    else
    {
        builder.Append("<br />");
        builder.Append(reader[0]);
    }
}
string result = builder.ToString();

Ответ 3

Это всего лишь комбинация нескольких лучших идей:

public static class Extensions
{

    public static string JoinStrings(this DataReader reader, int ColumnIndex, string delimiter)
    {
        var result = new StringBuidler();
        var delim = String.Empty;
        while (reader.Read())
        {
           result.Append(delim).Append(reader[ColumnIndex].ToString());
           delim = delimiter;
        }
        return result.ToString();
    }
}

Теперь все, что вам нужно сделать, это вызвать его так:

string result = reader.JoinStrings(0, "<br/>");

Ответ 4

Другое решение .Net 2.0 - измените порядок:

reader.Read();
StringBuilder sb = new StringBuilder(reader[0]);
while(reader.Read())
{
  sb.Append("<br />");
  sb.Append(reader[0]);
}
string result = sb.ToString();

Ответ 5

public class Separator 
{

    private string sep;
    private bool first = true;

    public Separator(string sep) 
    {
        this.sep = sep;
    }

    public virtual string ToString() 
    {
        string reply = first ? "" : sep;
        first = false;
        return reply;
    }
}

var sep = new Separator("<br/>");
var builder = new StringBuilder();
while (reader.Read())
{
    builder.Append (sep.ToString()) ;
    builder.Append (reader[0]) ;
}