A = string.Concat("abc","def")
B = "abc" + "def"
最近我一直在困惑,为什么很多人会说,相比B.绝对是做了更快的处理,但是,事情是,他们只会说,因为有人这么说,或者因为它就是这样。我想我可以从这里听到更好的解释。
编译器如何处理这些字符串?
谢谢!
A = string.Concat("abc","def")
B = "abc" + "def"
最近我一直在困惑,为什么很多人会说,相比B.绝对是做了更快的处理,但是,事情是,他们只会说,因为有人这么说,或者因为它就是这样。我想我可以从这里听到更好的解释。
编译器如何处理这些字符串?
谢谢!
我加入C#编译器团队时做的第一件事是我重写了字符串连接的优化器。美好时光。
如前所述,常量字符串的字符串concats是在编译时完成。非常量字符串做一些花哨的东西:
a + b --> String.Concat(a, b)
a + b + c --> String.Concat(a, b, c)
a + b + c + d --> String.Concat(a, b, c, d)
a + b + c + d + e --> String.Concat(new String[] { a, b, c, d, e })
这些优化的好处是,该String.Concat方法可以看看所有的参数,确定它们的长度的总和,然后做出一个大的字符串,可以掌握所有结果。
这里有一个有趣的一个。假设你有一个返回字符串的方法M:
s = M() + "";
如果M()返回null,那么结果是空字符串。 (null + empty是空的。)如果M不返回null,那么结果不会因空字符串的串联而改变。因此,这实际上是优化的,因为根本不是对String.Concat的调用!它变成
s = M() ?? ""
整洁,呃?
在C#中,字符串的加法运算符只是String.Concat的语法糖。您可以通过在反射器中打开输出组件来验证。
需要注意的另一件事是,如果您的代码中包含字符串文字(或常量)(如示例中所示),编译器甚至将其更改为B = "abcdef"
。
但是,如果使用String.Concat
带有两个字符串文字或常量,String.Concat仍然会被调用,跳过优化,因此+
操作实际上会更快。
所以,总结一下:
stringA + stringB
变得String.Concat(stringA, stringB)
。
"abc" + "def"
成为"abcdef
“
String.Concat("abc", "def")
保持不变
别的东西,我刚做了尝试:
在C++/CLI,"abc" + "def" + "ghi
” 实际上是翻译成String.Concat(String.Concat("abc", "def"), "ghi")
事实上,B的期间解析编译时间。你将以B = "abcdef"
结束,而对于A,连接被推迟到执行时间。
要添加到此,* not *面对文字时使用`+`将被转换为`string.Concat()` – Joey 2011-01-21 10:47:34
如果字符串文字,在你的问题,然后分配给B
的字符串的连接将在编译时完成。你的榜样转化为:
string a = string.Concat("abc", "def");
string b = "abcdef";
如果字符串不是字面值,则编译器会将+
操作转化为Concat
电话。
所以这...
string x = GetStringFromSomewhere();
string y = GetAnotherString();
string a = string.Concat(x, y);
string b = x + y;
...被翻译成这个在编译时:
string x = GetStringFromSomewhere();
string y = GetAnotherString();
string a = string.Concat(x, y);
string b = string.Concat(x, y);
在这种特殊情况下,两者实际上是相同的。编译器会将第二个变体(使用+
运算符的变体)转换为第一个变体Concat的调用。
那么,如果两个实际包含的字符串变量被连接在一起。
此代码:
B = "abc" + "def";
实际上转变成这样,无连接的所有:
B = "abcdef";
这是可以做到,因为加法的结果可以在编译时计算,所以编译器会这样做。
但是,如果你使用的是这样的:
A = String.Concat(stringVariable1, stringVariable2);
B = stringVariable1 + stringVariable2;
然后他们两个会产生相同的代码。
但是,我想知道那些“多”的说法,因为我认为它有些不同。
我认为他们说的是字符串连接不好,你应该使用StringBuilder或类似的。
举例来说,如果你这样做:
String s = "test";
for (int index = 1; index <= 10000; index++)
s = s + "test";
那么会发生什么情况是,通过循环每次迭代中,你将建立一个新的字符串,而让旧有资格进行垃圾回收。
此外,每个这样的新字符串都会复制旧字符串的所有内容,这意味着您将移动大量内存。
而下面的代码:
StringBuilder sb = new StringBuilder("test");
for (int index = 1; index <= 10000; index++)
sb.Append("test");
将改为使用内部缓冲区,比什么需要更大一些,以防万一你需要更多的文字追加到它。当该缓冲区变满时,将分配一个更大的新缓冲区,并将旧的剩下的一个留给垃圾收集。
所以在使用内存和CPU使用率方面,后来变种好得多。
除此之外,我会尽力避免过分关注“代码变量X比Y更好”,超出了你已有的经验。举例来说,我使用StringBuilder现在只是因为我知道的情况,但这并不是说所有我利用它来编写代码实际需要它。
尽量避免花费时间微优化代码,直到你知道你有一个瓶颈。那时候,通常先测量,稍后再测量的提示仍然有效。
对于这种大小的字符串,无关紧要 – 2011-01-21 10:44:49