一个
string实例是不可变的。创建后便无法更改。似乎更改字符串的任何 *** 作都将返回一个新实例:
string foo = "Foo";// returns a new string instance instead of changing the old onestring 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可以这样做,并且最好不要打赌)。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)