【问题标题】:How should I concatenate strings?我应该如何连接字符串?
【发布时间】:2010-06-23 14:59:24
【问题描述】:

这些示例之间有区别吗?在这种情况下我应该使用哪个?

var str1 = "abc" + dynamicString + dynamicString2;

var str2 = String.Format("abc{0}{1}", dynamicString, dynamicString2);

var str3 = new StringBuilder("abc").
    Append(dynamicString).
    Append(dynamicString2).
    ToString();

var str4 = String.Concat("abc", dynamicString, dynamicString2);

有类似的问题:

这个问题是询问每种情况下会发生什么,这些示例的真正输出是什么?它们有什么区别?在这种情况下我应该在哪里使用它们?

【问题讨论】:

  • 顺便说一下,根据 C# 规范,字符串上的 + 运算符映射到 String.Concat
  • 各位,这不是重复的,我不管哪个效率更高。
  • 对我来说看起来很重复。当然,旧问题的许多答案都与这个问题有关。这也不是唯一的骗局——.NET 中存在大量关于字符串连接的问题。但也许有些人会不同意并投票重新开放 - 这取决于他们。
  • @George,另一个问题(和答案)的重点完全在于速度。那里接受的答案很糟糕。
  • @Bruno 回答您的问题,请参阅:stackoverflow.com/questions/2607985/…stackoverflow.com/questions/21078/… 实际上,第二个问题实际上回答了您的问题。是的,你的问题之前已经被问过了,无穷无尽。

标签: c# .net string string-concatenation


【解决方案1】:

只要您不处理非常多 (100+) 的字符串或非常大的 (长度 > 10000) 字符串,唯一的标准就是可读性。

对于这种规模的问题,请使用+。为了便于阅读,将 + 重载添加到字符串类中。

对于更复杂的构图以及需要替换或格式化时,请使用string.Format()

在组合许多片段(数百个或更多)或非常大的片段(长度 >> 1000)时使用StringBuilder。 StringBuilder 没有可读性功能,它只是为了提高性能。

【讨论】:

  • 可能还值得考虑被连接的字符串的大小。如果你要说连接 10 个大字符串,那么使用 StringBuilder 是值得的。
  • @Chaos:是的,但它们必须非常大,处理这些将是一个单独的主题
  • 我只是想插话一句半智能评论。帮助我度过一天。 :)
  • @Chaos,我明白了,我说你是对的。我有时会遇到这样的概念,即 100 个字符是“大”,而超过 1000 个字符是“巨大”。在答案中,我们应该在这些形容词上加上大致数字。我的错误也是,我编辑了一点。
  • 你说得很有道理。通常我会认为我对其他程序员的一般知识是理所当然的。我会更加努力地更加明确。此外,您的答案比重复问题中接受的答案要好得多。
【解决方案2】:

从所有答案中收集信息,结果是这样的:

+ 运算符与String.Concat 相同,可用于循环外的小连接,可用于小型任务。

在编译时,+ 运算符在静态时生成单个字符串,而 String.Concat 生成表达式 str = str1 + str2; 即使它们是静态的。

String.FormatStringBuilder.. (示例3)相同,只是String.Format 会验证参数并使用参数的长度实例化内部StringBuilder

String.Format应该在需要格式化字符串时使用,并连接简单的字符串。

StringBuilder 应在需要连接大字符串或循环使用时使用。

【讨论】:

    【解决方案3】:

    在您的场景中使用 + 运算符。

    只有在您的字符串中混合了变量和静态数据时,我才会使用 String.Format() 方法。例如:

    string result=String.Format(
        "Today {0} scored {1} {2} and {3} points against {4}",..);
    
    //looks nicer than
    string result = "Today " + playerName + " scored " + goalCount + " " + 
        scoreType + " and " + pointCount + " against " + opposingTeam;
    

    我看不出使用 StringBuilder 的意义,因为您已经在处理三个字符串文字了。

    我个人只在处理字符串数组时使用 Concat。

    【讨论】:

      【解决方案4】:

      我的经验法则是,如果您正在执行相对少量的连接(String.Format,而在连接将很大或可能会很大的时候使用StringBuilder。如果我有一个数组并且不需要任何格式,我会使用String.Join

      如果你有一个可枚举的集合,你也可以在 LINQ 中使用 Aggregate 函数: http://msdn.microsoft.com/en-us/library/bb548651.aspx

      【讨论】:

      • @Xander 刚刚指出 String.Format 在服务下使用了 StringBuilder。如果这是真的,那么我猜 String.Fromat 与 StringBuilder 是一个可怕的比较。在这种情况下,如果您不打算太浪费内存,最好使用 '+=' 进行连接。
      • 你是 Xander 的律师吗?如果有人指着grand canion说-跳..你要跳吗?
      【解决方案5】:

      @Jerod Houghtelling Answer

      实际上 String.Format 在幕后使用了 StringBuilder(如果需要,可以在 String.Format 上使用反射)

      我一般同意以下answer

      【讨论】:

      • + 运算符是否也使用 StringBuilder?
      • 什么?你确定吗?我确实在 string.format 和 sb.append 和 sb 之间进行了测试。我认为你的反射器当时喝醉了
      • @BrunoLM:不,字符串是不可变的,所以当您使用 + 运算符时,您实际上会收到一个新的字符串实例。
      • @Bobb 它实际上创建了一个new StringBuilder,附加字符串,应用format 并返回sb.ToString()
      • @BrunoLM - 是的,String.Format 正在做更多的工作,因此它比直接使用 StringBuilder 慢一点。
      【解决方案6】:

      @Xander。我相信你这个人。但是我的代码显示 sb 比 string.format 快。

      打败这个:

      Stopwatch sw = new Stopwatch();
      sw.Start();
      
      for (int i = 0; i < 10000; i++)
      {
          string r = string.Format("ABC{0}{1}{2}", i, i-10, 
              "dasdkadlkdjakdljadlkjdlkadjalkdj");
      }
      
      sw.Stop();
      Console.WriteLine("string.format: " + sw.ElapsedTicks);
      
      sw.Reset();
      sw.Start();
      for (int i = 0; i < 10000; i++)
      {
          StringBuilder sb = new StringBuilder();
          string r = sb.AppendFormat("ABC{0}{1}{2}", i, i - 10,
              "dasdkadlkdjakdljadlkjdlkadjalkdj").ToString();
      }
      
      sw.Stop();
      Console.WriteLine("AppendFormat: " + sw.ElapsedTicks);
      

      【讨论】:

      • 我不久前也进行了比较 - 有更快的解决方案 - 当您在课堂生命中创建一次 SB,然后在 sb.AppendFormat 之前使用 sb.Clear。
      • 它们之间唯一的区别是String.FormatStringBuilder builder = new StringBuilder(format.Length + (args.Length * 8));这样实例化StringBuilder并且有一个参数验证。这可能是造成微小差异的原因。
      • 另外 - 使用 StartNew() 而不是重置/启动。
      • @Bruno - 如果你每天做几百万次这样的手术 - 相信我 - 我会 - 差别不小。
      • 是的,我同意了。但这样的情况不太可能发生。但不管怎样,直接使用StringBuilder比String.Format快,这是毫无疑问的。
      【解决方案7】:

      理解字符串是不可变的很重要,它们不会改变。因此,任何时候您更改、添加、修改或任何字符串 - 它都会在内存中创建字符串的新“版本”,然后将旧版本用于垃圾收集。所以是这样的:

      string output = firstName.ToUpper().ToLower() + "test";
      

      这将创建一个字符串(用于输出),然后在内存中创建三个其他字符串(一个用于:ToUpper()、ToLower() 的输出,然后一个用于连接“test”)。

      因此,除非您使用 StringBuilder 或 string.Format,否则您所做的任何其他事情都会在内存中创建额外的字符串实例。这当然是循环内部的一个问题,您最终可能会得到成百上千个额外的字符串。希望有帮助

      【讨论】:

        【解决方案8】:

        请务必记住,字符串的行为与常规对象不同。 取以下代码:

        string s3 = "Hello ";
        string s3 += "World";
        

        这段代码将在堆上创建一个新字符串并将“Hello”放入其中。然后堆栈上的字符串对象将指向它(就像常规对象一样)。

        然后第 2 行将在堆“Hello World”上创建第二个字符串,并将堆栈上的对象指向它。在调用垃圾收集器之前,初始堆栈分配仍然存在。

        所以....如果您在调用垃圾收集器之前有大量这些调用,您可能会浪费大量内存。

        【讨论】:

          【解决方案9】:

          我看到没有人知道这个方法:

          string Color = "red";
          Console.WriteLine($"The apple is {Color}");
          

          【讨论】:

            【解决方案10】:
            var str3 = new StringBuilder
                .AppendFormat("abc{0}{1}", dynamicString, dynamicString2).ToString(); 
            

            上面的代码是最快的。所以如果你想快速使用它。如果您不在乎,请使用其他任何东西。

            【讨论】:

            • String.Format() 在幕后使用 StringBuilder,所以这也好不到哪里去。
            • @JoelCoehoorn 非常感谢投反对票的伙伴。我知道在评论和投反对票之前阅读太多了。我的回答是StringBuilder。但你是不存在的SO部落的法师..你不在乎..
            • 这不是我的反对意见,但由于这段代码甚至不应该编译(缺少 StringBuilder 构造函数的括号),所以看到一个我并不感到惊讶。
            猜你喜欢
            • 1970-01-01
            • 2011-07-15
            • 1970-01-01
            • 2012-03-11
            • 1970-01-01
            • 1970-01-01
            • 2020-10-29
            • 2011-02-12
            • 2015-07-21
            相关资源
            最近更新 更多