文中对String和StringBuilder的用法有一些偏差,首先,str = str.SubString(0, str.Length - 1)和str = str.SubString(1)的效率应该相差不大,String.SubString(int)的实现如下:
public
string
Substring(
int
startIndex)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
{
return this.Substring(startIndex, this.Length - startIndex);
}
因为SubString的两个重载如果需要得到相同长度的子串,分配内存和拷贝数据的时间消耗应当是差不多的。
StringBuilder的ToString方法提供了一个重载,如下:
public
string
ToString(
int
startIndex,
int
length)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
{
return this.m_StringValue.Substring(startIndex, length);
}
m_StringValue是一个string的实例,用以维持StringBuilder内部的值。因为SubString只涉及到内存分配和拷贝,而设置StringBuilder的Length时,需要更新StringBuilder的状态,并且最终使用时仍需要一次ToString()操作,在set_Length和ToString()时都可能会产生新的string实例,因此两种用法效率上的差别是无法直观判断的,需要通过测试来确定。现在的项目中我使用的是设置Length的方式,但有意图要测试一下ToString()的情况,以确定是否需要修改。
StringBuilder是一个expensive的对象,构建时代价比较大,因此除非有大量的或是无法预知次数的字符串操作,否则可以用string的操作来代替。原文中的几个功能都可以用string类的方法来实现。
首先是实现包含n个空格的字符串,有如下两种方式,效率都比较高:
string
str1
=
String.Empty.PadRight(
10
);
string
str2
=
new
String(
'
'
,
10
);
除了空格外,PadRight也可以指定其他的填充字符。
要生成类似于"a,b,c,d,e,f"这样的字符串,可以用String类的静态方法String.Join,代码如下:
string
str
=
String.Join(
"
,
"
,
new
string
[]
{"a", "b", "c", "d", "e"}
);
StringBuilder可以用来进行大量的字符串操作,但是构建StringBuilder的代码比较大,因此对于简单的字符串连接操作,可以使用String.Concat(params string[])方法。实际上,C#的编译器会为字符串的operator +生成调用String.Concat(params string[])的中间代码。编译器也为多个字符串的连接做了优化,例如以下四个字符串相连接,仅生成一次String.Concat(params string[])调用,而不是三次字符串连接。
string
str1
=
"
hello
"
;
string
str2
=
"
world
"
;
string
str
=
str1
+
"
"
+
str2
+
"
!
"
;
string
str1
=
"
hello
"
;
string
str2
=
"
world
"
;
int
i
=
2
;
string
str
=
str1
+
"
"
+
i
+
str2
+
"
!
"
;
因为i是Int32,因此根据Overload的规则,编译器最终会产生对String.Concat(params object[])的调用,这个方法的执行过程与String.Concat(params string[])类似,但会为每一个参数调用ToString()操作,即便此参数是string类的实例,因此,为了减少这一开销,应当如下编写:
string
str1
=
"
hello
"
;
string
str2
=
"
world
"
;
int
i
=
2
;
string
str
=
str1
+
"
"
+
i.ToString()
+
str2
+
"
!
"
;
最后,要说明的是string.PadRight及string.Join,还有string的构造函数,其最终依赖的实现方法声明都类似于:
[MethodImpl(MethodImplOptions.InternalCall)]
public
static
extern
string
Join(
string
separator,
string
[] value,
int
startIndex,
int
count);
这类代码都是内部实现的,效率非常高。
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0be121fa5b8988fbabbbc526af3b0fc0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
因为SubString的两个重载如果需要得到相同长度的子串,分配内存和拷贝数据的时间消耗应当是差不多的。
StringBuilder的ToString方法提供了一个重载,如下:
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0be121fa5b8988fbabbbc526af3b0fc0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/587e34b10dcf5efbc0859b53470a2db3.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/4fd96b3cf02f4c7b5c8964ac8167f7af.gif)
m_StringValue是一个string的实例,用以维持StringBuilder内部的值。因为SubString只涉及到内存分配和拷贝,而设置StringBuilder的Length时,需要更新StringBuilder的状态,并且最终使用时仍需要一次ToString()操作,在set_Length和ToString()时都可能会产生新的string实例,因此两种用法效率上的差别是无法直观判断的,需要通过测试来确定。现在的项目中我使用的是设置Length的方式,但有意图要测试一下ToString()的情况,以确定是否需要修改。
StringBuilder是一个expensive的对象,构建时代价比较大,因此除非有大量的或是无法预知次数的字符串操作,否则可以用string的操作来代替。原文中的几个功能都可以用string类的方法来实现。
首先是实现包含n个空格的字符串,有如下两种方式,效率都比较高:
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
除了空格外,PadRight也可以指定其他的填充字符。
要生成类似于"a,b,c,d,e,f"这样的字符串,可以用String类的静态方法String.Join,代码如下:
![](https://i-blog.csdnimg.cn/blog_migrate/34031c708bfe702fe82d01ff5c6593aa.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0be121fa5b8988fbabbbc526af3b0fc0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/b854634c0904529d4018c4c3336be836.gif)
StringBuilder可以用来进行大量的字符串操作,但是构建StringBuilder的代码比较大,因此对于简单的字符串连接操作,可以使用String.Concat(params string[])方法。实际上,C#的编译器会为字符串的operator +生成调用String.Concat(params string[])的中间代码。编译器也为多个字符串的连接做了优化,例如以下四个字符串相连接,仅生成一次String.Concat(params string[])调用,而不是三次字符串连接。
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
String.Concat会分析传入的多个参数,一次性分配结果所需的内存,并将参数值依次拷贝到结果字符串的相应部分,效率还是相当高的。
那么,以下的代码会生成对哪个方法的调用呢?
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
因为i是Int32,因此根据Overload的规则,编译器最终会产生对String.Concat(params object[])的调用,这个方法的执行过程与String.Concat(params string[])类似,但会为每一个参数调用ToString()操作,即便此参数是string类的实例,因此,为了减少这一开销,应当如下编写:
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
最后,要说明的是string.PadRight及string.Join,还有string的构造函数,其最终依赖的实现方法声明都类似于:
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/f0cd6c7f9e7ae96feae062cb48f670f0.gif)
这类代码都是内部实现的,效率非常高。