【问题标题】:Difference between string and StringBuilder in C#C#中字符串和StringBuilder的区别
【发布时间】:2010-06-18 12:09:47
【问题描述】:

stringStringBuilder 有什么区别?

另外,有什么例子可以帮助理解?

【问题讨论】:

标签: c# string stringbuilder


【解决方案1】:

string 实例是不可变的。创建后无法更改。任何看似更改字符串的操作都会返回一个新实例:

string foo = "Foo";
// returns a new string instance instead of changing the old one
string bar = foo.Replace('o', 'a');
string baz = foo + "bar"; // ditto here

不可变对象有一些不错的属性,例如它们可以跨线程使用而不必担心同步问题,或者您可以直接分发您的私有支持字段而不必担心有人更改了他们不应该更改的对象(请参阅数组或可变列表,如果不需要,通常需要在返回它们之前复制它们)。但是如果使用不小心,它们可能会产生严重的性能问题(几乎任何事情 - 如果您需要一个以执行速度为荣的语言的示例,那么请查看 C 的字符串操作函数)。

当您需要一个 可变 字符串时,例如您正在分段构建或更改很多内容的字符串,那么您将需要一个 StringBuilder,它是一个字符缓冲区可以改变。这在很大程度上会影响性能。如果您想要一个可变字符串,而是使用普通的 string 实例来执行它,那么您最终会不必要地创建和销毁大量对象,而 StringBuilder 实例本身会发生变化,从而不需要许多新对象.

简单的例子:下面的例子会让很多程序员痛不欲生:

string s = string.Empty;
for (i = 0; i < 1000; i++) {
  s += i.ToString() + " ";
}

您最终将在此处创建 2001 个字符串,其中 2000 个被丢弃。使用 StringBuilder 的相同示例:

StringBuilder sb = new StringBuilder();
for (i = 0; i < 1000; i++) {
  sb.Append(i);
  sb.Append(' ');
}

这应该减少内存分配器的压力:-)

但是应该注意,C# 编译器在处理字符串时相当聪明。比如下面这行

string foo = "abc" + "def" + "efg" + "hij";

将被编译器加入,在运行时只留下一个字符串。类似地,诸如

之类的行
string foo = a + b + c + d + e + f;

将被改写为

string foo = string.Concat(a, b, c, d, e, f);

因此您不必为五个无意义的串联付费,这将是一种天真的处理方式。这不会像上面那样将您保存在循环中(除非编译器展开循环,但我认为只有 JIT 可能实际上这样做,最好不要打赌)。

【讨论】:

  • “任何似乎更改字符串的操作都会返回一个新实例”但是为什么呢?什么是理由??为什么字符串不是可变的?为什么 CLR 创建新实例并删除以前的实例??
  • @Jeson:不可变数据结构有很多不错的属性,其中大部分与默认编写更安全的代码有关。您不必担心您的字符串会因为另一个线程在它们上工作而改变。而且您不必返回类内部字符串的副本来防止消费者篡改您的字段。
【解决方案2】:

String 与 StringBuilder

  • 字符串

    • 在系统命名空间下

    • 不可变(只读)实例

    • 当值发生连续变化时性能会下降

    • 线程安全

  • StringBuilder(可变字符串)

    1. 在 System.Text 命名空间下
    2. 可变实例
    3. 显示更好的性能,因为对现有实例进行了新的更改

有关此主题的描述性文章以及大量使用 ObjectIDGenerator 的示例,请关注 this link

相关堆栈溢出问题:Mutability of string when string doesn't change in C#

【讨论】:

    【解决方案3】:

    字符串

    String 实例是不可变的,这意味着在创建它之后我们无法更改它。如果我们对 String 执行任何操作,它将返回一个新实例(在内存中创建一个新实例),而不是修改现有实例值。

    StringBuilder

    StringBuilder 是可变的,也就是说,如果我们对 StringBuilder 执行任何操作,它都会更新现有的实例值,并且不会创建新的实例。

    Difference between String and StringBuilder

    【讨论】:

      【解决方案4】:

      主要区别:

      字符串是不可变的。这意味着您根本无法修改字符串;修改的结果是一个新的字符串。如果您打算附加到字符串,这将无效。

      StringBuilder 是可变的。它可以以任何方式进行修改,并且不需要创建新实例。工作完成后,可以调用 ToString() 来获取字符串。

      字符串可以参与实习。这意味着具有相同内容的字符串可能具有相同的地址。 StringBuilder 不能被实习。

      String 是唯一可以有引用文字的类。

      【讨论】:

        【解决方案5】:

        字符串是不可变的,即如果您更改它们的值,旧值将被丢弃并在堆上创建一个新值,而在字符串构建器中我们可以修改现有值而不创建新值。

        所以性能方面的字符串生成器是有益的,因为我们不需要占用更多的内存空间。

        【讨论】:

          【解决方案6】:

          字符串是不可变的,这意味着当您创建一个字符串时,您永远无法更改它。相反,它将创建一个新字符串来存储新值,如果您需要大量更改字符串变量的值,这可能会降低效率。

          StringBuilder 可以用来模拟一个可变的字符串,所以当你需要对一个字符串进行大量的更改时它是很好的。

          【讨论】:

            【解决方案7】:

            当您需要分多个步骤构建字符串时,StringBuilder 会为您提供帮助。

            不要这样做:

            String x = "";
            x += "first ";
            x += "second ";
            x += "third ";
            

            你会的

            StringBuilder sb = new StringBuilder("");
            sb.Append("first ");
            sb.Append("second ");
            sb.Append("third");
            String x = sb.ToString();
            

            最终效果是一样的,但是StringBuilder会占用更少的内存,运行速度会更快。它不会创建一个将两者连接起来的新字符串,而是单独创建块,并且只有在最后才会将它们联合起来。

            【讨论】:

              【解决方案8】:

              来自StringBuilder Class documentation

              String 对象是不可变的。每次使用 System.String 类中的一种方法时,都会在内存中创建一个新的字符串对象,这需要为该新对象分配新的空间。在需要对字符串执行重复修改的情况下,与创建新 String 对象相关的开销可能会很昂贵。当您想要修改字符串而不创建新对象时,可以使用 System.Text.StringBuilder 类。例如,在一个循环中将多个字符串连接在一起时,使用 StringBuilder 类可以提高性能。

              【讨论】:

                【解决方案9】:

                字符串 (System.String) 是在 .NET 框架内定义的类型。 String 类是不可变的。这意味着每次对 System.String 实例执行操作时,.NET 编译器都会创建该字符串的新实例。此操作对开发者是隐藏的。

                System.Text.StringBuilder 是表示可变字符串的类。该类提供了一些有用的方法,使用户能够管理由 StringBuilder 包装的字符串。请注意,所有操作都是在同一个 StringBuilder 实例上进行的。

                Microsoft 鼓励使用 StringBuilder,因为它在内存使用方面更有效。

                【讨论】:

                  【解决方案10】:

                  String 连接的复杂度也是 O(N2),而 StringBuffer 的复杂度是 O(N)。

                  因此,我们在循环中使用串联可能会出现性能问题,因为每次都会创建大量新对象。

                  【讨论】:

                    【解决方案11】:

                    如果您想与字符串生成器一起遍历字符串,您可以使用Clone 方法...它返回一个对象,因此您可以使用 ToString 方法转换为字符串...:)

                    【讨论】:

                      【解决方案12】:

                      System.String 是一个可变对象,这意味着它在创建后无法修改。请参考 Difference between string and StringBuilder in C#? 以获得更好的理解。

                      【讨论】:

                      • 请添加一些来自elink的内容
                      【解决方案13】:

                      String 是不可变的类型。这意味着每当您开始将字符串相互连接时,您每次都在创建新字符串。如果您这样做多次,最终会产生大量堆开销和内存不足的风险。

                      StringBuilder 实例用于能够将字符串附加到同一个实例,当您在其上调用 ToString 方法时创建一个字符串。

                      由于实例化 StringBuilder 对象的开销,Microsoft 表示当您有超过 5-10 个字符串连接时使用它很有用。

                      对于示例代码,我建议你看看这里:

                      【讨论】:

                        猜你喜欢
                        • 2012-02-27
                        • 2010-09-17
                        • 1970-01-01
                        • 1970-01-01
                        • 2010-09-26
                        相关资源
                        最近更新 更多