StringBuilder字符串是不可变的吗?

时间:2009-02-02 06:14:18

标签: c# .net string

StringBuilder作为一种比简单连接字符串更快的字符串操作工具而享有盛誉。无论这是否属实,我都不知道StringBuilder操作的结果及它们产生的字符串。

快速搜索Reflector表明StringBuilder.ToString()并不总是返回副本,有时它似乎返回内部字符串的实例。它似乎也使用一些内部函数来操作内部字符串。

如果我这样做,我该怎么办?

string s = "Yo Ho Ho";
StringBuilder sb = new StringBuilder(s);
string newString = sb.ToString();
sb.Append(" and a bottle of rum.");
string newNewString = sb.ToString();

newString和newNewString是不同的字符串实例还是相同的?我试图通过反射器解决这个问题,而我只是不太了解所有事情。

这段代码怎么样?

StringBuilder sb = new StringBuilder("Foo\n");
StringReader sr = new StringReader(sb.ToString());
string s = sr.ReadLine();
sb.Append("Bar\n");
s = sr.ReadLine();

最后一个语句会返回null还是“Bar”?如果它返回一个或其他,这个定义或未定义的行为?换句话说,我能依靠吗?

关于这个主题的文档非常简洁,我不愿意依赖观察到的行为而不是规范。

4 个答案:

答案 0 :(得分:10)

在mscorlib之外,System.String的任何实例都是不可变的,句点。

StringBuilder在内部对字符串进行了一些有趣的操作,但在一天结束时,它不会向您返回一个字符串,然后以您的代码可见的方式对其进行变更。

关于StringBuilder.ToString()的后续调用是返回String的相同实例还是具有相同值的不同String,这取决于实现,您不应该依赖此行为。

答案 1 :(得分:4)

newStringnewNewString是不同的字符串实例。

虽然ToString()返回当前字符串,但它会清除当前的线程变量。这意味着下次你追加时,它会在追加之前获取当前字符串的副本。

我不是完全确定你在第二个问题中得到了什么,但是s将为null:如果文件中的最后一个字符是行终止字符( s)对于前一行,该行被认为在这些字符和文件末尾之间有一个空行。之前读过的字符串对此没有任何影响。

答案 2 :(得分:3)

  

newStringnewNewString   不同的string实例或   相同?我试图解决这个问题   通过反射器,我只是不完全   了解一切。

他们是不同的string个实例:newString是“Yo Ho Ho”,newNewString是“Yo Ho Ho and a bottle of rum.”。 strings是不可变的,当你调用StringBuilder.ToString()时,该方法返回一个表示当前状态的不可变string

  

最后一个语句会返回null还是   “Bar”?如果它返回一个或其他   另外,这是定义还是未定义   行为?换句话说,我可以依靠   在它上面?

它将返回nullStringReader正在处理您在构造函数中传递给它的不可变string,因此它不受您对StringBuilder所做的任何操作的影响。

答案 3 :(得分:2)

这个类的全部目的是使字符串变为可变,所以它实际上是。我相信(但不确定)只有在没有对这个对象做过任何其他事情的情况下它才会返回相同的字符串。所以

之后
String s_old = "Foo";
StringBuilder sb = new StringBuilder(s_old);
String s_new = sb.ToString();

s_old与s_new相同,但不会出现任何其他情况。

我应该注意,对于Java编译器自动将多个字符串添加转换为使用StringBuilder(或类似但更快的StringBuffer)类的操作,我会非常惊讶.NET编译器也不会进行此转换。