【问题标题】:Separated string created in loop在循环中创建的分隔字符串
【发布时间】:2009-03-17 12:39:16
【问题描述】:

我正在寻找在循环中创建一个与另一个分隔的字符串的最佳方法。我的意思是,例如,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

【问题讨论】:

  • 他正在寻找通过迭代地将字符串组件添加在一起来创建字符串的最佳方法。
  • 好的,现在您的问题已被编辑,所以答案没有多大意义。 :) 但是看到在同一行中使用 StringBuilder 和 String.Concat 仍然让我很伤心。这也没有多大意义。 :)
  • 感谢提示!我已经编辑了

标签: c# .net sql loops


【解决方案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 />");

【讨论】:

  • 我同意,Join 在内部将所有字符串复制到同一个缓冲区,没有新的分配。
  • 所以你也在使用相同的 String.Join(String, IEnumerable.ToArray()) ——我认为这是最好的方法,不是吗?
  • 是的,我认为这是最好的方法。但在您的示例中,您正在创建该集合的两个副本。一个用于 List,一个用于 ToArray()。在我的,你只创建一个数组。
  • 我更喜欢扩展方法的方式。在我工作的代码中添加了几个非常相似的扩展方法。让事情变得更容易和可读......
  • Hmm.. 我以为 ToArray() 只是创建一个数组,然后立即传递给 String.Join。你的意思是这个数组是第二个副本,是吗?我还不知道如何使用'yield'语句。我一定要学,我会的。
【解决方案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();

【讨论】:

  • 看起来不错!我认为这是最好的“经典”解决方案,我的意思是 .NET 2.0,不使用扩展等。
【解决方案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();
    

    【讨论】:

    • 如果查询没有返回任何行,这将失败——但它真正需要的是另一个 if 语句,所以它还不错。
    • 确实会,但这里的很多解决方案都会这样做。阅读器返回的内容也没有数据类型转换,实际上将 StringReader 的值分配给结果没有意义,但它显示了这一点。
    【解决方案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]) ;
    }
    

    【讨论】:

    • 你有一个错误,但我修复了它。
    猜你喜欢
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    • 2021-10-26
    • 2015-12-05
    • 2015-12-04
    • 2011-06-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多